From acdc3dd3c0c1ca2a4d2e2cd89a8ff5a82b56c2f6 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 11 Jun 2021 21:12:27 +0100 Subject: [PATCH 001/386] Replace ?ed25519= with ?key= in peering URIs --- src/core/link.go | 2 +- src/multicast/multicast.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index 51b679a6..c0eb509f 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -75,7 +75,7 @@ func (l *links) call(u *url.URL, sintf string) error { // return fmt.Errorf("peer %s is not correctly formatted (%s)", uri, err) //} tcpOpts := tcpOptions{} - if pubkeys, ok := u.Query()["ed25519"]; ok && len(pubkeys) > 0 { + if pubkeys, ok := u.Query()["key"]; ok && len(pubkeys) > 0 { tcpOpts.pinnedEd25519Keys = make(map[keyArray]struct{}) for _, pubkey := range pubkeys { if sigPub, err := hex.DecodeString(pubkey); err == nil { diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 220be7fd..6f0e8f98 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -365,7 +365,7 @@ func (m *Multicast) listen() { }) if _, ok := interfaces[from.Zone]; ok { addr.Zone = "" - pin := fmt.Sprintf("/?ed25519=%s", hex.EncodeToString(key)) + pin := fmt.Sprintf("/?key=%s", hex.EncodeToString(key)) u, err := url.Parse("tcp://" + addr.String() + pin) if err != nil { m.log.Debugln("Call from multicast failed, parse error:", addr.String(), err) From 3815b13ad5e03180a737b53afb4170a9d9d0aabd Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 12 Jun 2021 05:58:14 -0500 Subject: [PATCH 002/386] use DialContext --- src/core/tcp.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/tcp.go b/src/core/tcp.go index 21a3ba79..c5487d5d 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -270,7 +270,9 @@ func (t *tcp) call(saddr string, options tcpOptions, sintf string) { if err != nil { return } - conn, err = dialer.Dial("tcp", saddr) + ctx, done := context.WithTimeout(context.Background(), default_timeout) + conn, err = dialer.(proxy.ContextDialer).DialContext(ctx, "tcp", saddr) + done() if err != nil { return } @@ -292,7 +294,6 @@ func (t *tcp) call(saddr string, options tcpOptions, sintf string) { } dialer := net.Dialer{ Control: t.tcpContext, - Timeout: time.Second * 5, } if sintf != "" { dialer.Control = t.getControl(sintf) @@ -338,7 +339,9 @@ func (t *tcp) call(saddr string, options tcpOptions, sintf string) { } } } - conn, err = dialer.Dial("tcp", dst.String()) + ctx, done := context.WithTimeout(context.Background(), default_timeout) + conn, err = dialer.DialContext(ctx, "tcp", dst.String()) + done() if err != nil { t.links.core.log.Debugf("Failed to dial %s: %s", callproto, err) return From 5b6f730f18d3e6804aad9e2c9ffb3790dfc60265 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 12 Jun 2021 06:06:39 -0500 Subject: [PATCH 003/386] keep a context in the core, use it for listen/dial, cancel it when closing --- src/core/core.go | 17 ++++++++++++----- src/core/tcp.go | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/core/core.go b/src/core/core.go index de916c1b..b17bf191 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -1,6 +1,7 @@ package core import ( + "context" "crypto/ed25519" "encoding/hex" "errors" @@ -31,6 +32,8 @@ type Core struct { links links log *log.Logger addPeerTimer *time.Timer + ctx context.Context + ctxCancel context.CancelFunc } func (c *Core) _init() error { @@ -57,6 +60,7 @@ func (c *Core) _init() error { // TODO check public against current.PublicKey, error if they don't match c.PacketConn, err = iw.NewPacketConn(c.secret) + c.ctx, c.ctxCancel = context.WithCancel(context.Background()) return err } @@ -67,6 +71,10 @@ func (c *Core) _addPeerLoop() { c.config.RLock() defer c.config.RUnlock() + if c.addPeerTimer == nil { + return + } + // Add peers from the Peers section for _, peer := range c.config.Peers { go func(peer string, intf string) { @@ -95,11 +103,9 @@ func (c *Core) _addPeerLoop() { } } - if c.addPeerTimer != nil { - c.addPeerTimer = time.AfterFunc(time.Minute, func() { - c.Act(nil, c._addPeerLoop) - }) - } + c.addPeerTimer = time.AfterFunc(time.Minute, func() { + c.Act(nil, c._addPeerLoop) + }) } // Start starts up Yggdrasil using the provided config.NodeConfig, and outputs @@ -152,6 +158,7 @@ func (c *Core) Stop() { // This function is unsafe and should only be ran by the core actor. func (c *Core) _stop() { + c.ctxCancel() c.PacketConn.Close() c.log.Infoln("Stopping...") if c.addPeerTimer != nil { diff --git a/src/core/tcp.go b/src/core/tcp.go index c5487d5d..c9bfd65f 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -153,7 +153,7 @@ func (t *tcp) listenURL(u *url.URL, sintf string) (*TcpListener, error) { func (t *tcp) listen(listenaddr string, upgrade *TcpUpgrade) (*TcpListener, error) { var err error - ctx := context.Background() + ctx := t.links.core.ctx lc := net.ListenConfig{ Control: t.tcpContext, } @@ -270,7 +270,7 @@ func (t *tcp) call(saddr string, options tcpOptions, sintf string) { if err != nil { return } - ctx, done := context.WithTimeout(context.Background(), default_timeout) + ctx, done := context.WithTimeout(t.links.core.ctx, default_timeout) conn, err = dialer.(proxy.ContextDialer).DialContext(ctx, "tcp", saddr) done() if err != nil { @@ -339,7 +339,7 @@ func (t *tcp) call(saddr string, options tcpOptions, sintf string) { } } } - ctx, done := context.WithTimeout(context.Background(), default_timeout) + ctx, done := context.WithTimeout(t.links.core.ctx, default_timeout) conn, err = dialer.DialContext(ctx, "tcp", dst.String()) done() if err != nil { From eeadffe4a5c08206ea30d70376fd1860397ebc7e Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 12 Jun 2021 06:07:33 -0500 Subject: [PATCH 004/386] move position of log line on shutdown --- src/core/core.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core.go b/src/core/core.go index b17bf191..bd2478fc 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -158,9 +158,9 @@ func (c *Core) Stop() { // This function is unsafe and should only be ran by the core actor. func (c *Core) _stop() { + c.log.Infoln("Stopping...") c.ctxCancel() c.PacketConn.Close() - c.log.Infoln("Stopping...") if c.addPeerTimer != nil { c.addPeerTimer.Stop() c.addPeerTimer = nil From 91235980af18b036240eda6c1d11383f580352fc Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 12 Jun 2021 07:03:32 -0500 Subject: [PATCH 005/386] fix logging for socks --- src/core/tcp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/tcp.go b/src/core/tcp.go index c9bfd65f..5c3e506b 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -277,7 +277,7 @@ func (t *tcp) call(saddr string, options tcpOptions, sintf string) { return } t.waitgroup.Add(1) - options.socksPeerAddr = conn.RemoteAddr().String() + options.socksPeerAddr = saddr if ch := t.handler(conn, false, options); ch != nil { <-ch } From bb66851c2b4b37d89c03e051d7a17e3ae0355f5f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 12 Jun 2021 21:46:17 +0100 Subject: [PATCH 006/386] Update dependencies --- go.mod | 22 +++++++++++---------- go.sum | 62 +++++++++++++++++++++++++++++++--------------------------- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index eb9065b8..1e27d93b 100644 --- a/go.mod +++ b/go.mod @@ -3,22 +3,24 @@ module github.com/yggdrasil-network/yggdrasil-go go 1.16 require ( - github.com/Arceliar/ironwood v0.0.0-20210606054635-3bd9d71bce77 + github.com/Arceliar/ironwood v0.0.0-20210606094153-1bd43ce71198 github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 - github.com/cheggaaa/pb/v3 v3.0.6 - github.com/fatih/color v1.10.0 // indirect + github.com/VividCortex/ewma v1.2.0 // indirect + github.com/cheggaaa/pb/v3 v3.0.8 + github.com/fatih/color v1.12.0 // indirect github.com/gologme/log v1.2.0 github.com/hashicorp/go-syslog v1.0.0 github.com/hjson/hjson-go v3.1.0+incompatible github.com/kardianos/minwinsvc v1.0.0 - github.com/mattn/go-runewidth v0.0.10 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mitchellh/mapstructure v1.4.1 - github.com/rivo/uniseg v0.2.0 // indirect github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect - golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 - golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b - golang.org/x/text v0.3.6-0.20210220033129-8f690f22cf1c - golang.zx2c4.com/wireguard v0.0.0-20210306175010-7e3b8371a1bf - golang.zx2c4.com/wireguard/windows v0.3.8 + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect + golang.org/x/net v0.0.0-20210610132358-84b48f89b13b + golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 + golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f + golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 + golang.zx2c4.com/wireguard/windows v0.3.14 ) diff --git a/go.sum b/go.sum index 9eb66d51..dab85269 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,15 @@ -github.com/Arceliar/ironwood v0.0.0-20210606054635-3bd9d71bce77 h1:KPX5rjNFU3ICdrOBP/TKSq2XWqkF5vqIH+rf/PYnH38= -github.com/Arceliar/ironwood v0.0.0-20210606054635-3bd9d71bce77/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= +github.com/Arceliar/ironwood v0.0.0-20210606094153-1bd43ce71198 h1:wLF+CSqm9DrPeT2dp1E4Xe5of8SyUxfJVxw8DHeT1YM= +github.com/Arceliar/ironwood v0.0.0-20210606094153-1bd43ce71198/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= -github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= -github.com/cheggaaa/pb/v3 v3.0.6 h1:ULPm1wpzvj60FvmCrX7bIaB80UgbhI+zSaQJKRfCbAs= -github.com/cheggaaa/pb/v3 v3.0.6/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA= +github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/gologme/log v1.2.0 h1:Ya5Ip/KD6FX7uH0S31QO87nCCSucKtF44TLbTtO7V4c= github.com/gologme/log v1.2.0/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= @@ -19,15 +20,14 @@ github.com/kardianos/minwinsvc v1.0.0 h1:+JfAi8IBJna0jY2dJGZqi7o15z13JelFIklJCAE github.com/kardianos/minwinsvc v1.0.0/go.mod h1:Bgd0oc+D0Qo3bBytmNtyRKVlp85dAloLKhfxanPFFRc= github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= -github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -40,14 +40,16 @@ github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvV github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -56,20 +58,22 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225014209-683adc9d29d7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305215415-5cdee2b1b5a0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b h1:ggRgirZABFolTmi3sn6Ivd9SipZwLedQ5wR0aAKnFxU= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6-0.20210220033129-8f690f22cf1c h1:SW/oilbeWd6f32u3ZvuYGqZ+wivcp//I3Dy/gByk7Wk= -golang.org/x/text v0.3.6-0.20210220033129-8f690f22cf1c/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= +golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.zx2c4.com/wireguard v0.0.0-20210225140808-70b7b7158fc9/go.mod h1:39ZQQ95hUxDxT7opsWy/rtfgvXXc8s30qfZ02df69Fo= -golang.zx2c4.com/wireguard v0.0.0-20210306175010-7e3b8371a1bf h1:AtdIMfzvVNPXN4kVY/yWS8mvpQogSwtCRJk2y/LBPpg= -golang.zx2c4.com/wireguard v0.0.0-20210306175010-7e3b8371a1bf/go.mod h1:ojGPy+9W6ZSM8anL+xC67fvh8zPQJwA6KpFOHyDWLX4= -golang.zx2c4.com/wireguard/windows v0.3.8 h1:FvfBEhdZZTwthLuPHdyP6zpivYL3enopxd4XpggAufM= -golang.zx2c4.com/wireguard/windows v0.3.8/go.mod h1:lm7dxHcBuzMNq706Ge1tZKZKw4+19vG9dLOhoDX05HQ= +golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= +golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 h1:wfOOSvHgIzTZ9h5Vb6yUFZNn7uf3bT7PeYsHOO7tYDM= +golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= +golang.zx2c4.com/wireguard/windows v0.3.14 h1:5yIDYyrQyGkLqV+tzY4ilMNeIvQeMXAz0glZz9u179A= +golang.zx2c4.com/wireguard/windows v0.3.14/go.mod h1:3P4IEAsb+BjlKZmpUXgy74c0iX9AVwwr3WcVJ8nPgME= From 1147ee19348af2df4dd0474cbe056d774710924b Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 13 Jun 2021 04:22:21 -0500 Subject: [PATCH 007/386] WIP moving IP-specific checks from tuntap to core --- src/core/api.go | 10 +- src/core/core.go | 27 ++- src/core/keystore.go | 295 +++++++++++++++++++++++++++++++ src/core/link.go | 4 +- src/{tuntap => core}/nodeinfo.go | 6 +- src/{tuntap => core}/proto.go | 20 +-- src/{tuntap => core}/types.go | 2 +- src/tuntap/keystore.go | 157 ---------------- src/tuntap/tun.go | 38 ---- 9 files changed, 339 insertions(+), 220 deletions(-) create mode 100644 src/core/keystore.go rename src/{tuntap => core}/nodeinfo.go (96%) rename src/{tuntap => core}/proto.go (95%) rename src/{tuntap => core}/types.go (96%) delete mode 100644 src/tuntap/keystore.go diff --git a/src/core/api.go b/src/core/api.go index f28b592a..bfccd66a 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -46,7 +46,7 @@ type Session struct { func (c *Core) GetSelf() Self { var self Self - s := c.PacketConn.PacketConn.Debug.GetSelf() + s := c.pc.PacketConn.Debug.GetSelf() self.Key = s.Key self.Root = s.Root self.Coords = s.Coords @@ -55,7 +55,7 @@ func (c *Core) GetSelf() Self { func (c *Core) GetPeers() []Peer { var peers []Peer - ps := c.PacketConn.PacketConn.Debug.GetPeers() + ps := c.pc.PacketConn.Debug.GetPeers() for _, p := range ps { var info Peer info.Key = p.Key @@ -69,7 +69,7 @@ func (c *Core) GetPeers() []Peer { func (c *Core) GetDHT() []DHTEntry { var dhts []DHTEntry - ds := c.PacketConn.PacketConn.Debug.GetDHT() + ds := c.pc.PacketConn.Debug.GetDHT() for _, d := range ds { var info DHTEntry info.Key = d.Key @@ -82,7 +82,7 @@ func (c *Core) GetDHT() []DHTEntry { func (c *Core) GetPaths() []PathEntry { var paths []PathEntry - ps := c.PacketConn.PacketConn.Debug.GetPaths() + ps := c.pc.PacketConn.Debug.GetPaths() for _, p := range ps { var info PathEntry info.Key = p.Key @@ -94,7 +94,7 @@ func (c *Core) GetPaths() []PathEntry { func (c *Core) GetSessions() []Session { var sessions []Session - ss := c.PacketConn.Debug.GetSessions() + ss := c.pc.Debug.GetSessions() for _, s := range ss { var info Session info.Key = s.Key diff --git a/src/core/core.go b/src/core/core.go index bd2478fc..cb34d894 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -25,11 +25,13 @@ type Core struct { // We're going to keep our own copy of the provided config - that way we can // guarantee that it will be covered by the mutex phony.Inbox - *iw.PacketConn + pc *iw.PacketConn config *config.NodeConfig // Config secret ed25519.PrivateKey public ed25519.PublicKey links links + proto protoHandler + store keyStore log *log.Logger addPeerTimer *time.Timer ctx context.Context @@ -59,8 +61,10 @@ func (c *Core) _init() error { c.public = c.secret.Public().(ed25519.PublicKey) // TODO check public against current.PublicKey, error if they don't match - c.PacketConn, err = iw.NewPacketConn(c.secret) + c.pc, err = iw.NewPacketConn(c.secret) c.ctx, c.ctxCancel = context.WithCancel(context.Background()) + c.store.init(c) + c.proto.init(c) return err } @@ -160,7 +164,7 @@ func (c *Core) Stop() { func (c *Core) _stop() { c.log.Infoln("Stopping...") c.ctxCancel() - c.PacketConn.Close() + c.pc.Close() if c.addPeerTimer != nil { c.addPeerTimer.Stop() c.addPeerTimer = nil @@ -173,3 +177,20 @@ func (c *Core) _stop() { */ c.log.Infoln("Stopped") } + +// Implement io.ReadWriteCloser + +func (c *Core) Read(p []byte) (n int, err error) { + n, err = c.store.readPC(p) + return +} + +func (c *Core) Write(p []byte) (n int, err error) { + n, err = c.store.writePC(p) + return +} + +func (c *Core) Close() error { + c.Stop() + return nil +} diff --git a/src/core/keystore.go b/src/core/keystore.go new file mode 100644 index 00000000..43424881 --- /dev/null +++ b/src/core/keystore.go @@ -0,0 +1,295 @@ +package core + +import ( + "crypto/ed25519" + "errors" + "fmt" + "sync" + "time" + + iwt "github.com/Arceliar/ironwood/types" + + "github.com/yggdrasil-network/yggdrasil-go/src/address" +) + +const keyStoreTimeout = 2 * time.Minute + +type keyArray [ed25519.PublicKeySize]byte + +type keyStore struct { + core *Core + address address.Address + subnet address.Subnet + mutex sync.Mutex + keyToInfo map[keyArray]*keyInfo + addrToInfo map[address.Address]*keyInfo + addrBuffer map[address.Address]*buffer + subnetToInfo map[address.Subnet]*keyInfo + subnetBuffer map[address.Subnet]*buffer + buf []byte // scratch space to prefix with typeSessionTraffic before sending +} + +type keyInfo struct { + key keyArray + address address.Address + subnet address.Subnet + timeout *time.Timer // From calling a time.AfterFunc to do cleanup +} + +type buffer struct { + packets [][]byte + timeout *time.Timer +} + +func (k *keyStore) init(core *Core) { + k.core = core + k.address = *address.AddrForKey(k.core.public) + k.subnet = *address.SubnetForKey(k.core.public) + k.core.pc.SetOutOfBandHandler(k.oobHandler) + k.keyToInfo = make(map[keyArray]*keyInfo) + k.addrToInfo = make(map[address.Address]*keyInfo) + k.addrBuffer = make(map[address.Address]*buffer) + k.subnetToInfo = make(map[address.Subnet]*keyInfo) + k.subnetBuffer = make(map[address.Subnet]*buffer) +} + +func (k *keyStore) sendToAddress(addr address.Address, bs []byte) { + k.mutex.Lock() + if info := k.addrToInfo[addr]; info != nil { + k.resetTimeout(info) + k.mutex.Unlock() + _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) + } else { + var buf *buffer + if buf = k.addrBuffer[addr]; buf == nil { + buf = new(buffer) + k.addrBuffer[addr] = buf + } + msg := append([]byte(nil), bs...) + buf.packets = append(buf.packets, msg) + if buf.timeout != nil { + buf.timeout.Stop() + } + buf.timeout = time.AfterFunc(keyStoreTimeout, func() { + k.mutex.Lock() + defer k.mutex.Unlock() + if nbuf := k.addrBuffer[addr]; nbuf == buf { + delete(k.addrBuffer, addr) + } + }) + k.mutex.Unlock() + k.sendKeyLookup(addr.GetKey()) + } +} + +func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { + k.mutex.Lock() + if info := k.subnetToInfo[subnet]; info != nil { + k.resetTimeout(info) + k.mutex.Unlock() + _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) + } else { + var buf *buffer + if buf = k.subnetBuffer[subnet]; buf == nil { + buf = new(buffer) + k.subnetBuffer[subnet] = buf + } + msg := append([]byte(nil), bs...) + buf.packets = append(buf.packets, msg) + if buf.timeout != nil { + buf.timeout.Stop() + } + buf.timeout = time.AfterFunc(keyStoreTimeout, func() { + k.mutex.Lock() + defer k.mutex.Unlock() + if nbuf := k.subnetBuffer[subnet]; nbuf == buf { + delete(k.subnetBuffer, subnet) + } + }) + k.mutex.Unlock() + k.sendKeyLookup(subnet.GetKey()) + } +} + +func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { + k.mutex.Lock() + var kArray keyArray + copy(kArray[:], key) + var info *keyInfo + if info = k.keyToInfo[kArray]; info == nil { + info = new(keyInfo) + info.key = kArray + info.address = *address.AddrForKey(ed25519.PublicKey(info.key[:])) + info.subnet = *address.SubnetForKey(ed25519.PublicKey(info.key[:])) + k.keyToInfo[info.key] = info + k.addrToInfo[info.address] = info + k.subnetToInfo[info.subnet] = info + k.resetTimeout(info) + k.mutex.Unlock() + if buf := k.addrBuffer[info.address]; buf != nil { + for _, bs := range buf.packets { + _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) + } + delete(k.addrBuffer, info.address) + } + if buf := k.subnetBuffer[info.subnet]; buf != nil { + for _, bs := range buf.packets { + _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) + } + delete(k.subnetBuffer, info.subnet) + } + } else { + k.resetTimeout(info) + k.mutex.Unlock() + } + return info +} + +func (k *keyStore) resetTimeout(info *keyInfo) { + if info.timeout != nil { + info.timeout.Stop() + } + info.timeout = time.AfterFunc(keyStoreTimeout, func() { + k.mutex.Lock() + defer k.mutex.Unlock() + if nfo := k.keyToInfo[info.key]; nfo == info { + delete(k.keyToInfo, info.key) + } + if nfo := k.addrToInfo[info.address]; nfo == info { + delete(k.addrToInfo, info.address) + } + if nfo := k.subnetToInfo[info.subnet]; nfo == info { + delete(k.subnetToInfo, info.subnet) + } + }) +} + +func (k *keyStore) oobHandler(fromKey, toKey ed25519.PublicKey, data []byte) { + if len(data) != 1+ed25519.SignatureSize { + return + } + sig := data[1:] + switch data[0] { + case typeKeyLookup: + snet := *address.SubnetForKey(toKey) + if snet == k.subnet && ed25519.Verify(fromKey, toKey[:], sig) { + // This is looking for at least our subnet (possibly our address) + // Send a response + k.sendKeyResponse(fromKey) + } + case typeKeyResponse: + // TODO keep a list of something to match against... + // Ignore the response if it doesn't match anything of interest... + if ed25519.Verify(fromKey, toKey[:], sig) { + k.update(fromKey) + } + } +} + +func (k *keyStore) sendKeyLookup(partial ed25519.PublicKey) { + sig := ed25519.Sign(k.core.secret, partial[:]) + bs := append([]byte{typeKeyLookup}, sig...) + _ = k.core.pc.SendOutOfBand(partial, bs) +} + +func (k *keyStore) sendKeyResponse(dest ed25519.PublicKey) { + sig := ed25519.Sign(k.core.secret, dest[:]) + bs := append([]byte{typeKeyResponse}, sig...) + _ = k.core.pc.SendOutOfBand(dest, bs) +} + +func (k *keyStore) maxSessionMTU() uint64 { + const sessionTypeOverhead = 1 + return k.core.pc.MTU() - sessionTypeOverhead +} + +func (k *keyStore) readPC(p []byte) (int, error) { + for { + bs := p + n, from, err := k.core.pc.ReadFrom(bs) + if err != nil { + return n, err + } + if n == 0 { + continue + } + switch bs[0] { + case typeSessionTraffic: + // This is what we want to handle here + case typeSessionProto: + var key keyArray + copy(key[:], from.(iwt.Addr)) + data := append([]byte(nil), bs[1:n]...) + k.core.proto.handleProto(nil, key, data) + continue + default: + continue + } + bs = bs[1:n] + if len(bs) == 0 { + continue + } + if bs[0]&0xf0 != 0x60 { + continue // not IPv6 + } + if len(bs) < 40 { + continue + } + /* TODO ICMP packet too big + if len(bs) > int(tun.MTU()) { + ptb := &icmp.PacketTooBig{ + MTU: int(tun.mtu), + Data: bs[:40], + } + if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil { + _, _ = tun.core.WriteTo(packet, from) + } + continue + } + */ + var srcAddr, dstAddr address.Address + var srcSubnet, dstSubnet address.Subnet + copy(srcAddr[:], bs[8:]) + copy(dstAddr[:], bs[24:]) + copy(srcSubnet[:], bs[8:]) + copy(dstSubnet[:], bs[24:]) + if dstAddr != k.address && dstSubnet != k.subnet { + continue // bad local address/subnet + } + info := k.update(ed25519.PublicKey(from.(iwt.Addr))) + if srcAddr != info.address && srcSubnet != info.subnet { + continue // bad remote address/subnet + } + n = copy(p, bs) + return n, nil + } +} + +func (k *keyStore) writePC(bs []byte) (int, error) { + if bs[0]&0xf0 != 0x60 { + return 0, errors.New("not an IPv6 packet") // not IPv6 + } + if len(bs) < 40 { + strErr := fmt.Sprint("undersized IPv6 packet, length:", len(bs)) + return 0, errors.New(strErr) + } + var srcAddr, dstAddr address.Address + var srcSubnet, dstSubnet address.Subnet + copy(srcAddr[:], bs[8:]) + copy(dstAddr[:], bs[24:]) + copy(srcSubnet[:], bs[8:]) + copy(dstSubnet[:], bs[24:]) + if srcAddr != k.address && srcSubnet != k.subnet { + return 0, errors.New("wrong source address") + } + k.buf = append(k.buf[:0], typeSessionTraffic) + k.buf = append(k.buf, bs...) + if dstAddr.IsValid() { + k.sendToAddress(dstAddr, k.buf) + } else if dstSubnet.IsValid() { + k.sendToSubnet(dstSubnet, k.buf) + } else { + return 0, errors.New("invalid destination address") + } + return len(bs), nil +} diff --git a/src/core/link.go b/src/core/link.go index c0eb509f..295a8ad6 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -20,8 +20,6 @@ import ( //"github.com/Arceliar/phony" // TODO? use instead of mutexes ) -type keyArray [ed25519.PublicKeySize]byte - type links struct { core *Core mutex sync.RWMutex // protects links below @@ -231,7 +229,7 @@ func (intf *link) handler() (chan struct{}, error) { intf.links.core.log.Infof("Connected %s: %s, source %s", strings.ToUpper(intf.info.linkType), themString, intf.info.local) // Run the handler - err = intf.links.core.PacketConn.HandleConn(ed25519.PublicKey(intf.info.key[:]), intf.conn) + err = intf.links.core.pc.HandleConn(ed25519.PublicKey(intf.info.key[:]), intf.conn) // TODO don't report an error if it's just a 'use of closed network connection' if err != nil { intf.links.core.log.Infof("Disconnected %s: %s, source %s; error: %s", diff --git a/src/tuntap/nodeinfo.go b/src/core/nodeinfo.go similarity index 96% rename from src/tuntap/nodeinfo.go rename to src/core/nodeinfo.go index a61a4429..30644710 100644 --- a/src/tuntap/nodeinfo.go +++ b/src/core/nodeinfo.go @@ -1,4 +1,4 @@ -package tuntap +package core import ( "encoding/hex" @@ -129,7 +129,7 @@ func (m *nodeinfo) _sendReq(key keyArray, callback func(nodeinfo NodeInfoPayload if callback != nil { m._addCallback(key, callback) } - _, _ = m.proto.tun.core.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) + _, _ = m.proto.core.pc.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) } func (m *nodeinfo) handleReq(from phony.Actor, key keyArray) { @@ -146,7 +146,7 @@ func (m *nodeinfo) handleRes(from phony.Actor, key keyArray, info NodeInfoPayloa func (m *nodeinfo) _sendRes(key keyArray) { bs := append([]byte{typeSessionProto, typeProtoNodeInfoResponse}, m._getNodeInfo()...) - _, _ = m.proto.tun.core.WriteTo(bs, iwt.Addr(key[:])) + _, _ = m.proto.core.pc.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff diff --git a/src/tuntap/proto.go b/src/core/proto.go similarity index 95% rename from src/tuntap/proto.go rename to src/core/proto.go index 62b21563..24d54caf 100644 --- a/src/tuntap/proto.go +++ b/src/core/proto.go @@ -1,4 +1,4 @@ -package tuntap +package core import ( "encoding/hex" @@ -31,15 +31,15 @@ type reqInfo struct { type protoHandler struct { phony.Inbox - tun *TunAdapter + core *Core nodeinfo nodeinfo sreqs map[keyArray]*reqInfo preqs map[keyArray]*reqInfo dreqs map[keyArray]*reqInfo } -func (p *protoHandler) init(tun *TunAdapter) { - p.tun = tun +func (p *protoHandler) init(core *Core) { + p.core = core p.nodeinfo.init(p) p.sreqs = make(map[keyArray]*reqInfo) p.preqs = make(map[keyArray]*reqInfo) @@ -103,7 +103,7 @@ func (p *protoHandler) sendGetSelfRequest(key keyArray, callback func([]byte)) { } func (p *protoHandler) _handleGetSelfRequest(key keyArray) { - self := p.tun.core.GetSelf() + self := p.core.GetSelf() res := map[string]string{ "key": hex.EncodeToString(self.Key[:]), "coords": fmt.Sprintf("%v", self.Coords), @@ -144,12 +144,12 @@ func (p *protoHandler) sendGetPeersRequest(key keyArray, callback func([]byte)) } func (p *protoHandler) _handleGetPeersRequest(key keyArray) { - peers := p.tun.core.GetPeers() + peers := p.core.GetPeers() var bs []byte for _, pinfo := range peers { tmp := append(bs, pinfo.Key[:]...) const responseOverhead = 2 // 1 debug type, 1 getpeers type - if uint64(len(tmp))+responseOverhead > p.tun.maxSessionMTU() { + if uint64(len(tmp))+responseOverhead > p.core.store.maxSessionMTU() { break } bs = tmp @@ -186,12 +186,12 @@ func (p *protoHandler) sendGetDHTRequest(key keyArray, callback func([]byte)) { } func (p *protoHandler) _handleGetDHTRequest(key keyArray) { - dinfos := p.tun.core.GetDHT() + dinfos := p.core.GetDHT() var bs []byte for _, dinfo := range dinfos { tmp := append(bs, dinfo.Key[:]...) const responseOverhead = 2 // 1 debug type, 1 getdht type - if uint64(len(tmp))+responseOverhead > p.tun.maxSessionMTU() { + if uint64(len(tmp))+responseOverhead > p.core.store.maxSessionMTU() { break } bs = tmp @@ -209,7 +209,7 @@ func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) - _, _ = p.tun.core.WriteTo(bs, iwt.Addr(key[:])) + _, _ = p.core.pc.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff diff --git a/src/tuntap/types.go b/src/core/types.go similarity index 96% rename from src/tuntap/types.go rename to src/core/types.go index a8084e0c..e325b55e 100644 --- a/src/tuntap/types.go +++ b/src/core/types.go @@ -1,4 +1,4 @@ -package tuntap +package core // Out-of-band packet types const ( diff --git a/src/tuntap/keystore.go b/src/tuntap/keystore.go deleted file mode 100644 index 2eb79202..00000000 --- a/src/tuntap/keystore.go +++ /dev/null @@ -1,157 +0,0 @@ -package tuntap - -import ( - "crypto/ed25519" - "sync" - "time" - - iwt "github.com/Arceliar/ironwood/types" - - "github.com/yggdrasil-network/yggdrasil-go/src/address" -) - -const keyStoreTimeout = 2 * time.Minute - -type keyStore struct { - tun *TunAdapter - mutex sync.Mutex - keyToInfo map[keyArray]*keyInfo - addrToInfo map[address.Address]*keyInfo - addrBuffer map[address.Address]*buffer - subnetToInfo map[address.Subnet]*keyInfo - subnetBuffer map[address.Subnet]*buffer -} - -type keyArray [ed25519.PublicKeySize]byte - -type keyInfo struct { - key keyArray - address address.Address - subnet address.Subnet - timeout *time.Timer // From calling a time.AfterFunc to do cleanup -} - -type buffer struct { - packets [][]byte - timeout *time.Timer -} - -func (k *keyStore) init(tun *TunAdapter) { - k.tun = tun - k.keyToInfo = make(map[keyArray]*keyInfo) - k.addrToInfo = make(map[address.Address]*keyInfo) - k.addrBuffer = make(map[address.Address]*buffer) - k.subnetToInfo = make(map[address.Subnet]*keyInfo) - k.subnetBuffer = make(map[address.Subnet]*buffer) -} - -func (k *keyStore) sendToAddress(addr address.Address, bs []byte) { - k.mutex.Lock() - if info := k.addrToInfo[addr]; info != nil { - k.resetTimeout(info) - k.mutex.Unlock() - _, _ = k.tun.core.WriteTo(bs, iwt.Addr(info.key[:])) - } else { - var buf *buffer - if buf = k.addrBuffer[addr]; buf == nil { - buf = new(buffer) - k.addrBuffer[addr] = buf - } - msg := append([]byte(nil), bs...) - buf.packets = append(buf.packets, msg) - if buf.timeout != nil { - buf.timeout.Stop() - } - buf.timeout = time.AfterFunc(keyStoreTimeout, func() { - k.mutex.Lock() - defer k.mutex.Unlock() - if nbuf := k.addrBuffer[addr]; nbuf == buf { - delete(k.addrBuffer, addr) - } - }) - k.mutex.Unlock() - k.tun.sendKeyLookup(addr.GetKey()) - } -} - -func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { - k.mutex.Lock() - if info := k.subnetToInfo[subnet]; info != nil { - k.resetTimeout(info) - k.mutex.Unlock() - _, _ = k.tun.core.WriteTo(bs, iwt.Addr(info.key[:])) - } else { - var buf *buffer - if buf = k.subnetBuffer[subnet]; buf == nil { - buf = new(buffer) - k.subnetBuffer[subnet] = buf - } - msg := append([]byte(nil), bs...) - buf.packets = append(buf.packets, msg) - if buf.timeout != nil { - buf.timeout.Stop() - } - buf.timeout = time.AfterFunc(keyStoreTimeout, func() { - k.mutex.Lock() - defer k.mutex.Unlock() - if nbuf := k.subnetBuffer[subnet]; nbuf == buf { - delete(k.subnetBuffer, subnet) - } - }) - k.mutex.Unlock() - k.tun.sendKeyLookup(subnet.GetKey()) - } -} - -func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { - k.mutex.Lock() - var kArray keyArray - copy(kArray[:], key) - var info *keyInfo - if info = k.keyToInfo[kArray]; info == nil { - info = new(keyInfo) - info.key = kArray - info.address = *address.AddrForKey(ed25519.PublicKey(info.key[:])) - info.subnet = *address.SubnetForKey(ed25519.PublicKey(info.key[:])) - k.keyToInfo[info.key] = info - k.addrToInfo[info.address] = info - k.subnetToInfo[info.subnet] = info - k.resetTimeout(info) - k.mutex.Unlock() - if buf := k.addrBuffer[info.address]; buf != nil { - for _, bs := range buf.packets { - _, _ = k.tun.core.WriteTo(bs, iwt.Addr(info.key[:])) - } - delete(k.addrBuffer, info.address) - } - if buf := k.subnetBuffer[info.subnet]; buf != nil { - for _, bs := range buf.packets { - _, _ = k.tun.core.WriteTo(bs, iwt.Addr(info.key[:])) - } - delete(k.subnetBuffer, info.subnet) - } - } else { - k.resetTimeout(info) - k.mutex.Unlock() - } - return info -} - -func (k *keyStore) resetTimeout(info *keyInfo) { - if info.timeout != nil { - info.timeout.Stop() - } - info.timeout = time.AfterFunc(keyStoreTimeout, func() { - k.mutex.Lock() - defer k.mutex.Unlock() - if nfo := k.keyToInfo[info.key]; nfo == info { - delete(k.keyToInfo, info.key) - } - if nfo := k.addrToInfo[info.address]; nfo == info { - delete(k.addrToInfo, info.address) - } - if nfo := k.subnetToInfo[info.subnet]; nfo == info { - delete(k.subnetToInfo, info.subnet) - } - }) -} diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index f53f6dea..7b20bfb2 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -189,41 +189,3 @@ func (tun *TunAdapter) _stop() error { return nil } -func (tun *TunAdapter) oobHandler(fromKey, toKey ed25519.PublicKey, data []byte) { - if len(data) != 1+ed25519.SignatureSize { - return - } - sig := data[1:] - switch data[0] { - case typeKeyLookup: - snet := *address.SubnetForKey(toKey) - if snet == tun.subnet && ed25519.Verify(fromKey, toKey[:], sig) { - // This is looking for at least our subnet (possibly our address) - // Send a response - tun.sendKeyResponse(fromKey) - } - case typeKeyResponse: - // TODO keep a list of something to match against... - // Ignore the response if it doesn't match anything of interest... - if ed25519.Verify(fromKey, toKey[:], sig) { - tun.store.update(fromKey) - } - } -} - -func (tun *TunAdapter) sendKeyLookup(partial ed25519.PublicKey) { - sig := ed25519.Sign(tun.core.PrivateKey(), partial[:]) - bs := append([]byte{typeKeyLookup}, sig...) - _ = tun.core.SendOutOfBand(partial, bs) -} - -func (tun *TunAdapter) sendKeyResponse(dest ed25519.PublicKey) { - sig := ed25519.Sign(tun.core.PrivateKey(), dest[:]) - bs := append([]byte{typeKeyResponse}, sig...) - _ = tun.core.SendOutOfBand(dest, bs) -} - -func (tun *TunAdapter) maxSessionMTU() uint64 { - const sessionTypeOverhead = 1 - return tun.core.MTU() - sessionTypeOverhead -} From 45d6a1e6e57dbcd92ddeddb9e3d24bf3d47e1d7a Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 10:42:31 +0100 Subject: [PATCH 008/386] Revert "Build MSIs for Windows using CircleCI (#766)" This reverts commit f0a5cd542cbf995ead8f3683adf427bf77978b60. --- .circleci/config.yml | 46 ++++-------------------- appveyor.yml | 20 +++++++++++ contrib/msi/build-msi.sh | 78 ++++++++++++++++++++++++++-------------- 3 files changed, 78 insertions(+), 66 deletions(-) create mode 100644 appveyor.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 6e41648c..5ebd26e2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -162,43 +162,6 @@ jobs: paths: - upload - build-windows: - docker: - - image: circleci/golang:1.16 - - steps: - - checkout - - - run: - name: Create artifact upload directory and set variables - command: | - mkdir /tmp/upload - echo 'export CINAME=$(sh contrib/semver/name.sh)' >> $BASH_ENV - echo 'export CIVERSION=$(sh contrib/semver/version.sh --bare)' >> $BASH_ENV - git config --global user.email "$(git log --format='%ae' HEAD -1)"; - git config --global user.name "$(git log --format='%an' HEAD -1)"; - - - run: - name: Install tools - command: | - sudo apt-get update - sudo apt-get -y install msitools wixl - - - run: - name: Build for Windows - command: | - rm -f {yggdrasil,yggdrasilctl} - GOOS=windows GOARCH=amd64 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-amd64.exe && mv yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-windows-amd64.exe; - GOOS=windows GOARCH=386 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-i386.exe && mv yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-windows-i386.exe; - bash contrib/msi/build-msi.sh x64 - bash contrib/msi/build-msi.sh x86 - mv *.msi /tmp/upload - - - persist_to_workspace: - root: /tmp - paths: - - upload - build-other: docker: - image: circleci/golang:1.16 @@ -229,6 +192,13 @@ jobs: GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-amd64; GOOS=freebsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-i386 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-freebsd-i386; + - run: + name: Build for Windows + command: | + rm -f {yggdrasil,yggdrasilctl} + GOOS=windows GOARCH=amd64 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-amd64.exe && mv yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-windows-amd64.exe; + GOOS=windows GOARCH=386 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-i386.exe && mv yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-windows-i386.exe; + - persist_to_workspace: root: /tmp paths: @@ -252,11 +222,9 @@ workflows: - lint - build-linux - build-macos - - build-windows - build-other - upload: requires: - build-linux - build-macos - - build-windows - build-other diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..58724a24 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,20 @@ +version: '{build}' +pull_requests: + do_not_increment_build_number: true +os: Visual Studio 2017 +shallow_clone: false + +environment: + MSYS2_PATH_TYPE: inherit + CHERE_INVOKING: enabled_from_arguments + +build_script: +- cmd: >- + cd %APPVEYOR_BUILD_FOLDER% +- c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x64" +- c:\msys64\usr\bin\bash -lc "./contrib/msi/build-msi.sh x86" + +test: off + +artifacts: +- path: '*.msi' diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 57d4e81d..421481cd 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -1,7 +1,9 @@ -#!/bin/bash +#!/bin/sh # This script generates an MSI file for Yggdrasil for a given architecture. It -# needs to run on Linux or macOS with Go 1.16, wixl and msitools installed. +# needs to run on Windows within MSYS2 and Go 1.13 or later must be installed on +# the system and within the PATH. This is ran currently by Appveyor (see +# appveyor.yml in the repository root) for both x86 and x64. # # Author: Neil Alexander @@ -9,7 +11,7 @@ PKGARCH=$1 if [ "${PKGARCH}" == "" ]; then - echo "tell me the architecture: x86, x64 or arm" + echo "tell me the architecture: x86 or x64" exit 1 fi @@ -26,11 +28,28 @@ then git checkout ${APPVEYOR_REPO_BRANCH} fi +# Install prerequisites within MSYS2 +pacman -S --needed --noconfirm unzip git curl + +# Download the wix tools! +if [ ! -d wixbin ]; +then + curl -LO https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip + if [ `md5sum wix311-binaries.zip | cut -f 1 -d " "` != "47a506f8ab6666ee3cc502fb07d0ee2a" ]; + then + echo "wix package didn't match expected checksum" + exit 1 + fi + mkdir -p wixbin + unzip -o wix311-binaries.zip -d wixbin || ( + echo "failed to unzip WiX" + exit 1 + ) +fi + # Build Yggdrasil! -[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build -p -l "-aslr" -[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build -p -l "-aslr" -[ "${PKGARCH}" == "arm" ] && GOOS=windows GOARCH=arm CGO_ENABLED=0 ./build -p -l "-aslr" -#[ "${PKGARCH}" == "arm64" ] && GOOS=windows GOARCH=arm64 CGO_ENABLED=0 ./build +[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build +[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build # Create the postinstall script cat > updateconfig.bat << EOF @@ -39,9 +58,7 @@ if not exist %ALLUSERSPROFILE%\\Yggdrasil ( ) if not exist %ALLUSERSPROFILE%\\Yggdrasil\\yggdrasil.conf ( if exist yggdrasil.exe ( - if not exist %ALLUSERSPROFILE%\\Yggdrasil\\yggdrasil.conf ( - yggdrasil.exe -genconf > %ALLUSERSPROFILE%\\Yggdrasil\\yggdrasil.conf - ) + yggdrasil.exe -genconf > %ALLUSERSPROFILE%\\Yggdrasil\\yggdrasil.conf ) ) EOF @@ -55,16 +72,12 @@ PKGVERSIONMS=$(echo $PKGVERSION | tr - .) PKGGUID="54a3294e-a441-4322-aefb-3bb40dd022bb" PKGINSTFOLDER="ProgramFilesFolder" # Download the Wintun driver -curl -o wintun.zip https://www.wintun.net/builds/wintun-0.10.2.zip -unzip wintun.zip if [ $PKGARCH = "x64" ]; then - PKGWINTUNDLL=wintun/bin/amd64/wintun.dll + PKGMSMNAME=wintun-x64.msm + curl -o ${PKGMSMNAME} https://www.wintun.net/builds/wintun-amd64-0.7.msm || (echo "couldn't get wintun"; exit 1) elif [ $PKGARCH = "x86" ]; then - PKGWINTUNDLL=wintun/bin/x86/wintun.dll -elif [ $PKGARCH = "arm" ]; then - PKGWINTUNDLL=wintun/bin/arm/wintun.dll -#elif [ $PKGARCH = "arm64" ]; then -# PKGWINTUNDLL=wintun/bin/arm64/wintun.dll + PKGMSMNAME=wintun-x86.msm + curl -o ${PKGMSMNAME} https://www.wintun.net/builds/wintun-x86-0.7.msm || (echo "couldn't get wintun"; exit 1) else echo "wasn't sure which architecture to get wintun for" exit 1 @@ -87,7 +100,6 @@ cat > wix.xml << EOF Language="1033" Codepage="1252" Version="${PKGVERSIONMS}" - Platform="${PKGARCH}" Manufacturer="github.com/yggdrasil-network"> wix.xml << EOF Source="yggdrasil.exe" KeyPath="yes" /> - - wix.xml << EOF + + @@ -178,6 +190,13 @@ cat > wix.xml << EOF + + + UPGRADINGPRODUCTCODE + + + + wix.xml << EOF + Before="StartServices"> + NOT Installed AND NOT REMOVE + @@ -197,4 +218,7 @@ cat > wix.xml << EOF EOF # Generate the MSI -wixl -v wix.xml -a ${PKGARCH} -o ${PKGNAME}-${PKGVERSION}-${PKGARCH}.msi +CANDLEFLAGS="-nologo" +LIGHTFLAGS="-nologo -spdb -sice:ICE71 -sice:ICE61" +wixbin/candle $CANDLEFLAGS -out ${PKGNAME}-${PKGVERSION}-${PKGARCH}.wixobj -arch ${PKGARCH} wix.xml && \ +wixbin/light $LIGHTFLAGS -ext WixUtilExtension.dll -out ${PKGNAME}-${PKGVERSION}-${PKGARCH}.msi ${PKGNAME}-${PKGVERSION}-${PKGARCH}.wixobj From 3b669a15edf01722b9a68c74e6c1eb0987c017e2 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 10:47:14 +0100 Subject: [PATCH 009/386] Update build-msi.sh --- contrib/msi/build-msi.sh | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 421481cd..85cd8209 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -11,7 +11,7 @@ PKGARCH=$1 if [ "${PKGARCH}" == "" ]; then - echo "tell me the architecture: x86 or x64" + echo "tell me the architecture: x86, x64 or arm" exit 1 fi @@ -48,8 +48,10 @@ then fi # Build Yggdrasil! -[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build -[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build +[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build -p -l "-aslr" +[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build -p -l "-aslr" +[ "${PKGARCH}" == "arm" ] && GOOS=windows GOARCH=arm CGO_ENABLED=0 ./build -p -l "-aslr" +#[ "${PKGARCH}" == "arm64" ] && GOOS=windows GOARCH=arm64 CGO_ENABLED=0 ./build # Create the postinstall script cat > updateconfig.bat << EOF @@ -72,12 +74,16 @@ PKGVERSIONMS=$(echo $PKGVERSION | tr - .) PKGGUID="54a3294e-a441-4322-aefb-3bb40dd022bb" PKGINSTFOLDER="ProgramFilesFolder" # Download the Wintun driver +curl -o wintun.zip https://www.wintun.net/builds/wintun-0.11.zip +unzip wintun.zip if [ $PKGARCH = "x64" ]; then - PKGMSMNAME=wintun-x64.msm - curl -o ${PKGMSMNAME} https://www.wintun.net/builds/wintun-amd64-0.7.msm || (echo "couldn't get wintun"; exit 1) + PKGWINTUNDLL=wintun/bin/amd64/wintun.dll elif [ $PKGARCH = "x86" ]; then - PKGMSMNAME=wintun-x86.msm - curl -o ${PKGMSMNAME} https://www.wintun.net/builds/wintun-x86-0.7.msm || (echo "couldn't get wintun"; exit 1) + PKGWINTUNDLL=wintun/bin/x86/wintun.dll +elif [ $PKGARCH = "arm" ]; then + PKGWINTUNDLL=wintun/bin/arm/wintun.dll +#elif [ $PKGARCH = "arm64" ]; then +# PKGWINTUNDLL=wintun/bin/arm64/wintun.dll else echo "wasn't sure which architecture to get wintun for" exit 1 @@ -100,6 +106,7 @@ cat > wix.xml << EOF Language="1033" Codepage="1252" Version="${PKGVERSIONMS}" + Platform="${PKGARCH}" Manufacturer="github.com/yggdrasil-network"> wix.xml << EOF Source="yggdrasil.exe" KeyPath="yes" /> + + wix.xml << EOF - - @@ -190,13 +197,6 @@ cat > wix.xml << EOF - - - UPGRADINGPRODUCTCODE - - - - Date: Sun, 13 Jun 2021 04:54:06 -0500 Subject: [PATCH 010/386] mostly finish migration of IP stuff to core, tuntap is still responsible for ICMP PacketTooBig --- src/core/api.go | 25 +++++++++ src/core/core.go | 31 ++++------- src/core/keystore.go | 124 ++++++++++++++++++++++--------------------- src/core/proto.go | 2 +- src/tuntap/admin.go | 8 +-- src/tuntap/iface.go | 88 +++--------------------------- src/tuntap/tun.go | 21 ++------ 7 files changed, 114 insertions(+), 185 deletions(-) diff --git a/src/core/api.go b/src/core/api.go index bfccd66a..c886edf6 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -222,3 +222,28 @@ func (c *Core) RemovePeer(addr string, sintf string) error { func (c *Core) CallPeer(u *url.URL, sintf string) error { return c.links.call(u, sintf) } + +func (c *Core) PublicKey() ed25519.PublicKey { + return c.public +} + +func (c *Core) MaxMTU() uint64 { + return c.store.maxSessionMTU() +} + +// Implement io.ReadWriteCloser + +func (c *Core) Read(p []byte) (n int, err error) { + n, err = c.store.readPC(p) + return +} + +func (c *Core) Write(p []byte) (n int, err error) { + n, err = c.store.writePC(p) + return +} + +func (c *Core) Close() error { + c.Stop() + return nil +} diff --git a/src/core/core.go b/src/core/core.go index cb34d894..89d49177 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -5,6 +5,7 @@ import ( "crypto/ed25519" "encoding/hex" "errors" + "fmt" "io/ioutil" "net/url" "time" @@ -25,13 +26,13 @@ type Core struct { // We're going to keep our own copy of the provided config - that way we can // guarantee that it will be covered by the mutex phony.Inbox - pc *iw.PacketConn + pc *iw.PacketConn config *config.NodeConfig // Config secret ed25519.PrivateKey public ed25519.PublicKey links links - proto protoHandler - store keyStore + proto protoHandler + store keyStore log *log.Logger addPeerTimer *time.Timer ctx context.Context @@ -43,13 +44,13 @@ func (c *Core) _init() error { // Init sets up structs // Start launches goroutines that depend on structs being set up // This is pretty much required to completely avoid race conditions + c.config.RLock() + defer c.config.RUnlock() if c.log == nil { c.log = log.New(ioutil.Discard, "", 0) } - c.config.RLock() sigPriv, err := hex.DecodeString(c.config.PrivateKey) - c.config.RUnlock() if err != nil { return err } @@ -65,6 +66,9 @@ func (c *Core) _init() error { c.ctx, c.ctxCancel = context.WithCancel(context.Background()) c.store.init(c) c.proto.init(c) + if err := c.proto.nodeinfo.setNodeInfo(c.config.NodeInfo, c.config.NodeInfoPrivacy); err != nil { + return fmt.Errorf("setNodeInfo: %w", err) + } return err } @@ -177,20 +181,3 @@ func (c *Core) _stop() { */ c.log.Infoln("Stopped") } - -// Implement io.ReadWriteCloser - -func (c *Core) Read(p []byte) (n int, err error) { - n, err = c.store.readPC(p) - return -} - -func (c *Core) Write(p []byte) (n int, err error) { - n, err = c.store.writePC(p) - return -} - -func (c *Core) Close() error { - c.Stop() - return nil -} diff --git a/src/core/keystore.go b/src/core/keystore.go index 43424881..d8a808a2 100644 --- a/src/core/keystore.go +++ b/src/core/keystore.go @@ -17,7 +17,7 @@ const keyStoreTimeout = 2 * time.Minute type keyArray [ed25519.PublicKeySize]byte type keyStore struct { - core *Core + core *Core address address.Address subnet address.Subnet mutex sync.Mutex @@ -26,7 +26,6 @@ type keyStore struct { addrBuffer map[address.Address]*buffer subnetToInfo map[address.Subnet]*keyInfo subnetBuffer map[address.Subnet]*buffer - buf []byte // scratch space to prefix with typeSessionTraffic before sending } type keyInfo struct { @@ -45,7 +44,10 @@ func (k *keyStore) init(core *Core) { k.core = core k.address = *address.AddrForKey(k.core.public) k.subnet = *address.SubnetForKey(k.core.public) - k.core.pc.SetOutOfBandHandler(k.oobHandler) + if err := k.core.pc.SetOutOfBandHandler(k.oobHandler); err != nil { + err = fmt.Errorf("tun.core.SetOutOfBandHander: %w", err) + panic(err) + } k.keyToInfo = make(map[keyArray]*keyInfo) k.addrToInfo = make(map[address.Address]*keyInfo) k.addrBuffer = make(map[address.Address]*buffer) @@ -204,38 +206,39 @@ func (k *keyStore) maxSessionMTU() uint64 { } func (k *keyStore) readPC(p []byte) (int, error) { - for { - bs := p - n, from, err := k.core.pc.ReadFrom(bs) - if err != nil { - return n, err - } - if n == 0 { - continue - } - switch bs[0] { - case typeSessionTraffic: - // This is what we want to handle here - case typeSessionProto: - var key keyArray - copy(key[:], from.(iwt.Addr)) - data := append([]byte(nil), bs[1:n]...) - k.core.proto.handleProto(nil, key, data) - continue - default: - continue - } - bs = bs[1:n] - if len(bs) == 0 { - continue - } - if bs[0]&0xf0 != 0x60 { - continue // not IPv6 - } - if len(bs) < 40 { - continue - } - /* TODO ICMP packet too big + buf := make([]byte, k.core.pc.MTU(), 65535) + for { + bs := buf + n, from, err := k.core.pc.ReadFrom(bs) + if err != nil { + return n, err + } + if n == 0 { + continue + } + switch bs[0] { + case typeSessionTraffic: + // This is what we want to handle here + case typeSessionProto: + var key keyArray + copy(key[:], from.(iwt.Addr)) + data := append([]byte(nil), bs[1:n]...) + k.core.proto.handleProto(nil, key, data) + continue + default: + continue + } + bs = bs[1:n] + if len(bs) == 0 { + continue + } + if bs[0]&0xf0 != 0x60 { + continue // not IPv6 + } + if len(bs) < 40 { + continue + } + /* TODO? ICMP packet too big, for now tuntap sends this when needed if len(bs) > int(tun.MTU()) { ptb := &icmp.PacketTooBig{ MTU: int(tun.mtu), @@ -246,32 +249,32 @@ func (k *keyStore) readPC(p []byte) (int, error) { } continue } - */ - var srcAddr, dstAddr address.Address - var srcSubnet, dstSubnet address.Subnet - copy(srcAddr[:], bs[8:]) - copy(dstAddr[:], bs[24:]) - copy(srcSubnet[:], bs[8:]) - copy(dstSubnet[:], bs[24:]) - if dstAddr != k.address && dstSubnet != k.subnet { - continue // bad local address/subnet - } - info := k.update(ed25519.PublicKey(from.(iwt.Addr))) - if srcAddr != info.address && srcSubnet != info.subnet { - continue // bad remote address/subnet - } - n = copy(p, bs) - return n, nil + */ + var srcAddr, dstAddr address.Address + var srcSubnet, dstSubnet address.Subnet + copy(srcAddr[:], bs[8:]) + copy(dstAddr[:], bs[24:]) + copy(srcSubnet[:], bs[8:]) + copy(dstSubnet[:], bs[24:]) + if dstAddr != k.address && dstSubnet != k.subnet { + continue // bad local address/subnet } + info := k.update(ed25519.PublicKey(from.(iwt.Addr))) + if srcAddr != info.address && srcSubnet != info.subnet { + continue // bad remote address/subnet + } + n = copy(p, bs) + return n, nil + } } func (k *keyStore) writePC(bs []byte) (int, error) { - if bs[0]&0xf0 != 0x60 { + if bs[0]&0xf0 != 0x60 { return 0, errors.New("not an IPv6 packet") // not IPv6 } if len(bs) < 40 { - strErr := fmt.Sprint("undersized IPv6 packet, length:", len(bs)) - return 0, errors.New(strErr) + strErr := fmt.Sprint("undersized IPv6 packet, length:", len(bs)) + return 0, errors.New(strErr) } var srcAddr, dstAddr address.Address var srcSubnet, dstSubnet address.Subnet @@ -280,16 +283,17 @@ func (k *keyStore) writePC(bs []byte) (int, error) { copy(srcSubnet[:], bs[8:]) copy(dstSubnet[:], bs[24:]) if srcAddr != k.address && srcSubnet != k.subnet { - return 0, errors.New("wrong source address") + return 0, errors.New("wrong source address") } - k.buf = append(k.buf[:0], typeSessionTraffic) - k.buf = append(k.buf, bs...) + buf := make([]byte, 1+len(bs), 65535) + buf[0] = typeSessionTraffic + copy(buf[1:], bs) if dstAddr.IsValid() { - k.sendToAddress(dstAddr, k.buf) + k.sendToAddress(dstAddr, buf) } else if dstSubnet.IsValid() { - k.sendToSubnet(dstSubnet, k.buf) + k.sendToSubnet(dstSubnet, buf) } else { - return 0, errors.New("invalid destination address") + return 0, errors.New("invalid destination address") } return len(bs), nil } diff --git a/src/core/proto.go b/src/core/proto.go index 24d54caf..557ac1d5 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -31,7 +31,7 @@ type reqInfo struct { type protoHandler struct { phony.Inbox - core *Core + core *Core nodeinfo nodeinfo sreqs map[keyArray]*reqInfo preqs map[keyArray]*reqInfo diff --git a/src/tuntap/admin.go b/src/tuntap/admin.go index 9c9ceb67..80b2df00 100644 --- a/src/tuntap/admin.go +++ b/src/tuntap/admin.go @@ -34,8 +34,8 @@ func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) { } return res, nil }) - _ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler) - _ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler) - _ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler) - _ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) + //_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler) + //_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler) + //_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler) + //_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) } diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index cb13690a..8642a005 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -1,20 +1,8 @@ package tuntap import ( - "crypto/ed25519" - - "github.com/yggdrasil-network/yggdrasil-go/src/address" "golang.org/x/net/icmp" "golang.org/x/net/ipv6" - - //"github.com/yggdrasil-network/yggdrasil-go/src/crypto" - //"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" - - //"golang.org/x/net/icmp" - //"golang.org/x/net/ipv6" - - iwt "github.com/Arceliar/ironwood/types" - //"github.com/Arceliar/phony" ) const TUN_OFFSET_BYTES = 4 @@ -34,28 +22,8 @@ func (tun *TunAdapter) read() { begin := TUN_OFFSET_BYTES end := begin + n bs := buf[begin:end] - if bs[0]&0xf0 != 0x60 { - continue // not IPv6 - } - if len(bs) < 40 { - tun.log.Traceln("TUN iface read undersized ipv6 packet, length:", len(bs)) - continue - } - var srcAddr, dstAddr address.Address - var srcSubnet, dstSubnet address.Subnet - copy(srcAddr[:], bs[8:]) - copy(dstAddr[:], bs[24:]) - copy(srcSubnet[:], bs[8:]) - copy(dstSubnet[:], bs[24:]) - if srcAddr != tun.addr && srcSubnet != tun.subnet { - continue // Wrong source address - } - bs = buf[begin-1 : end] - bs[0] = typeSessionTraffic - if dstAddr.IsValid() { - tun.store.sendToAddress(dstAddr, bs) - } else if dstSubnet.IsValid() { - tun.store.sendToSubnet(dstSubnet, bs) + if _, err := tun.core.Write(bs); err != nil { + tun.log.Errorln("Unable to send packet:", err) } } } @@ -63,63 +31,23 @@ func (tun *TunAdapter) read() { func (tun *TunAdapter) write() { var buf [TUN_OFFSET_BYTES + 65535]byte for { - bs := buf[TUN_OFFSET_BYTES-1:] - n, from, err := tun.core.ReadFrom(bs) + bs := buf[TUN_OFFSET_BYTES:] + n, err := tun.core.Read(bs) if err != nil { + tun.log.Errorln("Exiting tun writer due to core read error:", err) return } - if n == 0 { - continue - } - switch bs[0] { - case typeSessionTraffic: - // This is what we want to handle here - if !tun.isEnabled { - continue // Drop traffic if the tun is disabled - } - case typeSessionProto: - var key keyArray - copy(key[:], from.(iwt.Addr)) - data := append([]byte(nil), bs[1:n]...) - tun.proto.handleProto(nil, key, data) - continue - default: - continue - } - bs = bs[1:n] - if len(bs) == 0 { - continue - } - if bs[0]&0xf0 != 0x60 { - continue // not IPv6 - } - if len(bs) < 40 { - continue - } - if len(bs) > int(tun.MTU()) { + if n > int(tun.MTU()) { ptb := &icmp.PacketTooBig{ MTU: int(tun.mtu), Data: bs[:40], } if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil { - _, _ = tun.core.WriteTo(packet, from) + _, _ = tun.core.Write(packet) } continue } - var srcAddr, dstAddr address.Address - var srcSubnet, dstSubnet address.Subnet - copy(srcAddr[:], bs[8:]) - copy(dstAddr[:], bs[24:]) - copy(srcSubnet[:], bs[8:]) - copy(dstSubnet[:], bs[24:]) - if dstAddr != tun.addr && dstSubnet != tun.subnet { - continue // bad local address/subnet - } - info := tun.store.update(ed25519.PublicKey(from.(iwt.Addr))) - if srcAddr != info.address && srcSubnet != info.subnet { - continue // bad remote address/subnet - } - bs = buf[:TUN_OFFSET_BYTES+len(bs)] + bs = buf[:TUN_OFFSET_BYTES+n] if _, err = tun.iface.Write(bs, TUN_OFFSET_BYTES); err != nil { tun.Act(nil, func() { if !tun.isOpen { diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 7b20bfb2..41da0070 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -9,7 +9,6 @@ package tuntap // TODO: Don't block in reader on writes that are pending searches import ( - "crypto/ed25519" "errors" "fmt" "net" @@ -34,7 +33,6 @@ type MTU uint16 // calling yggdrasil.Start(). type TunAdapter struct { core *core.Core - store keyStore config *config.NodeConfig log *log.Logger addr address.Address @@ -45,7 +43,6 @@ type TunAdapter struct { //mutex sync.RWMutex // Protects the below isOpen bool isEnabled bool // Used by the writer to drop sessionTraffic if not enabled - proto protoHandler } // Gets the maximum supported MTU for the platform based on the defaults in @@ -98,18 +95,8 @@ func MaximumMTU() uint64 { // the Yggdrasil core before this point and it must not be in use elsewhere. func (tun *TunAdapter) Init(core *core.Core, config *config.NodeConfig, log *log.Logger, options interface{}) error { tun.core = core - tun.store.init(tun) tun.config = config tun.log = log - tun.proto.init(tun) - tun.config.RLock() - if err := tun.proto.nodeinfo.setNodeInfo(tun.config.NodeInfo, tun.config.NodeInfoPrivacy); err != nil { - return fmt.Errorf("tun.proto.nodeinfo.setNodeInfo: %w", err) - } - tun.config.RUnlock() - if err := tun.core.SetOutOfBandHandler(tun.oobHandler); err != nil { - return fmt.Errorf("tun.core.SetOutOfBandHander: %w", err) - } return nil } @@ -132,8 +119,7 @@ func (tun *TunAdapter) _start() error { if tun.config == nil { return errors.New("no configuration available to TUN") } - sk := tun.core.PrivateKey() - pk := sk.Public().(ed25519.PublicKey) + pk := tun.core.PublicKey() tun.addr = *address.AddrForKey(pk) tun.subnet = *address.SubnetForKey(pk) addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1) @@ -144,8 +130,8 @@ func (tun *TunAdapter) _start() error { return nil } mtu := tun.config.IfMTU - if tun.maxSessionMTU() < mtu { - mtu = tun.maxSessionMTU() + if tun.core.MaxMTU() < mtu { + mtu = tun.core.MaxMTU() } if err := tun.setup(tun.config.IfName, addr, mtu); err != nil { return err @@ -188,4 +174,3 @@ func (tun *TunAdapter) _stop() error { } return nil } - From 63967462d98ef3f2adf55a7e8b5be604ef3fa361 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 10:58:15 +0100 Subject: [PATCH 011/386] Update MSI build again --- contrib/msi/build-msi.sh | 9 ++++---- contrib/msi/msversion.sh | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 contrib/msi/msversion.sh diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 85cd8209..7818e7a7 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -48,9 +48,9 @@ then fi # Build Yggdrasil! -[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build -p -l "-aslr" -[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build -p -l "-aslr" -[ "${PKGARCH}" == "arm" ] && GOOS=windows GOARCH=arm CGO_ENABLED=0 ./build -p -l "-aslr" +[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build -l "-aslr" +[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build -l "-aslr" +[ "${PKGARCH}" == "arm" ] && GOOS=windows GOARCH=arm CGO_ENABLED=0 ./build -l "-aslr" #[ "${PKGARCH}" == "arm64" ] && GOOS=windows GOARCH=arm64 CGO_ENABLED=0 ./build # Create the postinstall script @@ -67,7 +67,7 @@ EOF # Work out metadata for the package info PKGNAME=$(sh contrib/semver/name.sh) -PKGVERSION=$(sh contrib/semver/version.sh --bare) +PKGVERSION=$(sh contrib/msi/msversion.sh --bare) PKGVERSIONMS=$(echo $PKGVERSION | tr - .) [ "${PKGARCH}" == "x64" ] && \ PKGGUID="77757838-1a23-40a5-a720-c3b43e0260cc" PKGINSTFOLDER="ProgramFiles64Folder" || \ @@ -119,7 +119,6 @@ cat > wix.xml << EOF InstallScope="perMachine" Languages="1033" Compressed="yes" - Platform="${PKGARCH}" SummaryCodepage="1252" /> /dev/null) + +# Did getting the tag succeed? +if [ $? != 0 ] || [ -z "$TAG" ]; then + printf -- "unknown" + exit 0 +fi + +# Get the current branch +BRANCH=$(git symbolic-ref -q HEAD --short 2>/dev/null) + +# 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) +MINOR=$(echo $TAG | cut -c 2- | cut -d "." -f 2) +PATCH=$(echo $TAG | cut -c 2- | cut -d "." -f 3) + +# Output in the desired format +if [ $((PATCH)) -eq 0 ]; then + printf '%s%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" +else + printf '%s%d.%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" "$((PATCH))" +fi + +# Add the build tag on non-master branches +if [ "$BRANCH" != "master" ]; then + 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 + printf -- "-unknown" + exit 0 + fi + + # Is the build greater than zero? + if [ $((BUILD)) -gt 0 ]; then + printf -- "-%04d" "$((BUILD))" + fi +fi \ No newline at end of file From 272670b85b3efa81f9f04ee20c1435f6be03d96c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 11:03:01 +0100 Subject: [PATCH 012/386] Fix version numbers in MSI --- contrib/msi/build-msi.sh | 1 - contrib/msi/msversion.sh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 7818e7a7..8d40b2bb 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -106,7 +106,6 @@ cat > wix.xml << EOF Language="1033" Codepage="1252" Version="${PKGVERSIONMS}" - Platform="${PKGARCH}" Manufacturer="github.com/yggdrasil-network"> Date: Sun, 13 Jun 2021 11:04:27 +0100 Subject: [PATCH 013/386] Remove -aslr --- contrib/msi/build-msi.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 8d40b2bb..001de313 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -48,9 +48,9 @@ then fi # Build Yggdrasil! -[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build -l "-aslr" -[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build -l "-aslr" -[ "${PKGARCH}" == "arm" ] && GOOS=windows GOARCH=arm CGO_ENABLED=0 ./build -l "-aslr" +[ "${PKGARCH}" == "x64" ] && GOOS=windows GOARCH=amd64 CGO_ENABLED=0 ./build +[ "${PKGARCH}" == "x86" ] && GOOS=windows GOARCH=386 CGO_ENABLED=0 ./build +[ "${PKGARCH}" == "arm" ] && GOOS=windows GOARCH=arm CGO_ENABLED=0 ./build #[ "${PKGARCH}" == "arm64" ] && GOOS=windows GOARCH=arm64 CGO_ENABLED=0 ./build # Create the postinstall script From 38e05b5f4c1199ac08f1630a502429cf79594304 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 11:07:19 +0100 Subject: [PATCH 014/386] Download wintun on first pass --- contrib/msi/build-msi.sh | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 001de313..72fd0733 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -74,19 +74,22 @@ PKGVERSIONMS=$(echo $PKGVERSION | tr - .) PKGGUID="54a3294e-a441-4322-aefb-3bb40dd022bb" PKGINSTFOLDER="ProgramFilesFolder" # Download the Wintun driver -curl -o wintun.zip https://www.wintun.net/builds/wintun-0.11.zip -unzip wintun.zip -if [ $PKGARCH = "x64" ]; then - PKGWINTUNDLL=wintun/bin/amd64/wintun.dll -elif [ $PKGARCH = "x86" ]; then - PKGWINTUNDLL=wintun/bin/x86/wintun.dll -elif [ $PKGARCH = "arm" ]; then - PKGWINTUNDLL=wintun/bin/arm/wintun.dll -#elif [ $PKGARCH = "arm64" ]; then -# PKGWINTUNDLL=wintun/bin/arm64/wintun.dll -else - echo "wasn't sure which architecture to get wintun for" - exit 1 +if [ ! -d wintun ]; +then + curl -o wintun.zip https://www.wintun.net/builds/wintun-0.11.zip + unzip wintun.zip + if [ $PKGARCH = "x64" ]; then + PKGWINTUNDLL=wintun/bin/amd64/wintun.dll + elif [ $PKGARCH = "x86" ]; then + PKGWINTUNDLL=wintun/bin/x86/wintun.dll + elif [ $PKGARCH = "arm" ]; then + PKGWINTUNDLL=wintun/bin/arm/wintun.dll + #elif [ $PKGARCH = "arm64" ]; then + # PKGWINTUNDLL=wintun/bin/arm64/wintun.dll + else + echo "wasn't sure which architecture to get wintun for" + exit 1 + fi fi if [ $PKGNAME != "master" ]; then From 9b68ac570222ab7936e07e3e8b9a7e0f798b5214 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 11:13:02 +0100 Subject: [PATCH 015/386] Fix wintun hopefully --- contrib/msi/build-msi.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/contrib/msi/build-msi.sh b/contrib/msi/build-msi.sh index 72fd0733..fd4ac3f5 100644 --- a/contrib/msi/build-msi.sh +++ b/contrib/msi/build-msi.sh @@ -78,18 +78,18 @@ if [ ! -d wintun ]; then curl -o wintun.zip https://www.wintun.net/builds/wintun-0.11.zip unzip wintun.zip - if [ $PKGARCH = "x64" ]; then - PKGWINTUNDLL=wintun/bin/amd64/wintun.dll - elif [ $PKGARCH = "x86" ]; then - PKGWINTUNDLL=wintun/bin/x86/wintun.dll - elif [ $PKGARCH = "arm" ]; then - PKGWINTUNDLL=wintun/bin/arm/wintun.dll - #elif [ $PKGARCH = "arm64" ]; then - # PKGWINTUNDLL=wintun/bin/arm64/wintun.dll - else - echo "wasn't sure which architecture to get wintun for" - exit 1 - fi +fi +if [ $PKGARCH = "x64" ]; then + PKGWINTUNDLL=wintun/bin/amd64/wintun.dll +elif [ $PKGARCH = "x86" ]; then + PKGWINTUNDLL=wintun/bin/x86/wintun.dll +elif [ $PKGARCH = "arm" ]; then + PKGWINTUNDLL=wintun/bin/arm/wintun.dll +#elif [ $PKGARCH = "arm64" ]; then +# PKGWINTUNDLL=wintun/bin/arm64/wintun.dll +else + echo "wasn't sure which architecture to get wintun for" + exit 1 fi if [ $PKGNAME != "master" ]; then From 3393db8e77f752fdb3ed247d0461e5de693e7549 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 13 Jun 2021 05:25:13 -0500 Subject: [PATCH 016/386] move ICMP PacketTooBig sending into core --- src/core/api.go | 12 +++++++ src/core/keystore.go | 30 ++++++++++------- src/tuntap/icmpv6.go | 80 -------------------------------------------- src/tuntap/iface.go | 16 ++------- src/tuntap/tun.go | 1 + 5 files changed, 33 insertions(+), 106 deletions(-) delete mode 100644 src/tuntap/icmpv6.go diff --git a/src/core/api.go b/src/core/api.go index c886edf6..536b1a87 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -231,6 +231,18 @@ func (c *Core) MaxMTU() uint64 { return c.store.maxSessionMTU() } +// SetMTU can only safely be called after Init and before Start. +func (c *Core) SetMTU(mtu uint64) { + if mtu < 1280 { + mtu = 1280 + } + c.store.mtu = mtu +} + +func (c *Core) MTU() uint64 { + return c.store.mtu +} + // Implement io.ReadWriteCloser func (c *Core) Read(p []byte) (n int, err error) { diff --git a/src/core/keystore.go b/src/core/keystore.go index d8a808a2..d2c6c24a 100644 --- a/src/core/keystore.go +++ b/src/core/keystore.go @@ -7,6 +7,9 @@ import ( "sync" "time" + "golang.org/x/net/icmp" + "golang.org/x/net/ipv6" + iwt "github.com/Arceliar/ironwood/types" "github.com/yggdrasil-network/yggdrasil-go/src/address" @@ -26,6 +29,7 @@ type keyStore struct { addrBuffer map[address.Address]*buffer subnetToInfo map[address.Subnet]*keyInfo subnetBuffer map[address.Subnet]*buffer + mtu uint64 } type keyInfo struct { @@ -53,6 +57,7 @@ func (k *keyStore) init(core *Core) { k.addrBuffer = make(map[address.Address]*buffer) k.subnetToInfo = make(map[address.Subnet]*keyInfo) k.subnetBuffer = make(map[address.Subnet]*buffer) + k.mtu = 1280 // Default to something safe, expect user to set this } func (k *keyStore) sendToAddress(addr address.Address, bs []byte) { @@ -238,18 +243,19 @@ func (k *keyStore) readPC(p []byte) (int, error) { if len(bs) < 40 { continue } - /* TODO? ICMP packet too big, for now tuntap sends this when needed - if len(bs) > int(tun.MTU()) { - ptb := &icmp.PacketTooBig{ - MTU: int(tun.mtu), - Data: bs[:40], - } - if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil { - _, _ = tun.core.WriteTo(packet, from) - } - continue - } - */ + if len(bs) > int(k.mtu) { + // Using bs would make it leak off the stack, so copy to buf + buf := make([]byte, 40) + copy(buf, bs) + ptb := &icmp.PacketTooBig{ + MTU: int(k.mtu), + Data: buf[:40], + } + if packet, err := CreateICMPv6(buf[8:24], buf[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil { + _, _ = k.writePC(packet) + } + continue + } var srcAddr, dstAddr address.Address var srcSubnet, dstSubnet address.Subnet copy(srcAddr[:], bs[8:]) diff --git a/src/tuntap/icmpv6.go b/src/tuntap/icmpv6.go deleted file mode 100644 index b7461a2d..00000000 --- a/src/tuntap/icmpv6.go +++ /dev/null @@ -1,80 +0,0 @@ -package tuntap - -// The ICMPv6 module implements functions to easily create ICMPv6 -// packets. These functions, when mixed with the built-in Go IPv6 -// and ICMP libraries, can be used to send control messages back -// to the host. Examples include: -// - NDP messages, when running in TAP mode -// - Packet Too Big messages, when packets exceed the session MTU -// - Destination Unreachable messages, when a session prohibits -// incoming traffic - -import ( - "encoding/binary" - "net" - - "golang.org/x/net/icmp" - "golang.org/x/net/ipv6" -) - -type ICMPv6 struct{} - -// Marshal returns the binary encoding of h. -func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) { - b := make([]byte, 40) - b[0] |= byte(h.Version) << 4 - b[0] |= byte(h.TrafficClass) >> 4 - b[1] |= byte(h.TrafficClass) << 4 - b[1] |= byte(h.FlowLabel >> 16) - b[2] = byte(h.FlowLabel >> 8) - b[3] = byte(h.FlowLabel) - binary.BigEndian.PutUint16(b[4:6], uint16(h.PayloadLen)) - b[6] = byte(h.NextHeader) - b[7] = byte(h.HopLimit) - copy(b[8:24], h.Src) - copy(b[24:40], h.Dst) - return b, nil -} - -// Creates an ICMPv6 packet based on the given icmp.MessageBody and other -// parameters, complete with IP headers only, which can be written directly to -// a TUN adapter, or called directly by the CreateICMPv6L2 function when -// generating a message for TAP adapters. -func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) { - // Create the ICMPv6 message - icmpMessage := icmp.Message{ - Type: mtype, - Code: mcode, - Body: mbody, - } - - // Convert the ICMPv6 message into []byte - icmpMessageBuf, err := icmpMessage.Marshal(icmp.IPv6PseudoHeader(src, dst)) - if err != nil { - return nil, err - } - - // Create the IPv6 header - ipv6Header := ipv6.Header{ - Version: ipv6.Version, - NextHeader: 58, - PayloadLen: len(icmpMessageBuf), - HopLimit: 255, - Src: src, - Dst: dst, - } - - // Convert the IPv6 header into []byte - ipv6HeaderBuf, err := ipv6Header_Marshal(&ipv6Header) - if err != nil { - return nil, err - } - - // Construct the packet - responsePacket := make([]byte, ipv6.HeaderLen+ipv6Header.PayloadLen) - copy(responsePacket[:ipv6.HeaderLen], ipv6HeaderBuf) - copy(responsePacket[ipv6.HeaderLen:], icmpMessageBuf) - - // Send it back - return responsePacket, nil -} diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 8642a005..587c925e 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -1,10 +1,5 @@ package tuntap -import ( - "golang.org/x/net/icmp" - "golang.org/x/net/ipv6" -) - const TUN_OFFSET_BYTES = 4 func (tun *TunAdapter) read() { @@ -37,15 +32,8 @@ func (tun *TunAdapter) write() { tun.log.Errorln("Exiting tun writer due to core read error:", err) return } - if n > int(tun.MTU()) { - ptb := &icmp.PacketTooBig{ - MTU: int(tun.mtu), - Data: bs[:40], - } - if packet, err := CreateICMPv6(bs[8:24], bs[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil { - _, _ = tun.core.Write(packet) - } - continue + if !tun.isEnabled { + continue // Nothing to do, the tun isn't enabled } bs = buf[:TUN_OFFSET_BYTES+n] if _, err = tun.iface.Write(bs, TUN_OFFSET_BYTES); err != nil { diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 41da0070..dbba018b 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -139,6 +139,7 @@ func (tun *TunAdapter) _start() error { if tun.MTU() != mtu { tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", tun.config.IfMTU, tun.MTU(), MaximumMTU()) } + tun.core.SetMTU(tun.MTU()) tun.isOpen = true tun.isEnabled = true go tun.read() From 48938282b7c43b03392597919235932001c13f9f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 11:28:41 +0100 Subject: [PATCH 017/386] Upgrade appveyor runner 2017 -> 2019 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 58724a24..903014e7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ version: '{build}' pull_requests: do_not_increment_build_number: true -os: Visual Studio 2017 +os: Visual Studio 2019 shallow_clone: false environment: From c8938a3527db8e3ff225d52f2232c106f6ef332c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 11:34:59 +0100 Subject: [PATCH 018/386] Add missing icmpv6.go --- src/core/icmpv6.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/core/icmpv6.go diff --git a/src/core/icmpv6.go b/src/core/icmpv6.go new file mode 100644 index 00000000..d15fbbcb --- /dev/null +++ b/src/core/icmpv6.go @@ -0,0 +1,80 @@ +package core + +// The ICMPv6 module implements functions to easily create ICMPv6 +// packets. These functions, when mixed with the built-in Go IPv6 +// and ICMP libraries, can be used to send control messages back +// to the host. Examples include: +// - NDP messages, when running in TAP mode +// - Packet Too Big messages, when packets exceed the session MTU +// - Destination Unreachable messages, when a session prohibits +// incoming traffic + +import ( + "encoding/binary" + "net" + + "golang.org/x/net/icmp" + "golang.org/x/net/ipv6" +) + +type ICMPv6 struct{} + +// Marshal returns the binary encoding of h. +func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) { + b := make([]byte, 40) + b[0] |= byte(h.Version) << 4 + b[0] |= byte(h.TrafficClass) >> 4 + b[1] |= byte(h.TrafficClass) << 4 + b[1] |= byte(h.FlowLabel >> 16) + b[2] = byte(h.FlowLabel >> 8) + b[3] = byte(h.FlowLabel) + binary.BigEndian.PutUint16(b[4:6], uint16(h.PayloadLen)) + b[6] = byte(h.NextHeader) + b[7] = byte(h.HopLimit) + copy(b[8:24], h.Src) + copy(b[24:40], h.Dst) + return b, nil +} + +// Creates an ICMPv6 packet based on the given icmp.MessageBody and other +// parameters, complete with IP headers only, which can be written directly to +// a TUN adapter, or called directly by the CreateICMPv6L2 function when +// generating a message for TAP adapters. +func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) { + // Create the ICMPv6 message + icmpMessage := icmp.Message{ + Type: mtype, + Code: mcode, + Body: mbody, + } + + // Convert the ICMPv6 message into []byte + icmpMessageBuf, err := icmpMessage.Marshal(icmp.IPv6PseudoHeader(src, dst)) + if err != nil { + return nil, err + } + + // Create the IPv6 header + ipv6Header := ipv6.Header{ + Version: ipv6.Version, + NextHeader: 58, + PayloadLen: len(icmpMessageBuf), + HopLimit: 255, + Src: src, + Dst: dst, + } + + // Convert the IPv6 header into []byte + ipv6HeaderBuf, err := ipv6Header_Marshal(&ipv6Header) + if err != nil { + return nil, err + } + + // Construct the packet + responsePacket := make([]byte, ipv6.HeaderLen+ipv6Header.PayloadLen) + copy(responsePacket[:ipv6.HeaderLen], ipv6HeaderBuf) + copy(responsePacket[ipv6.HeaderLen:], icmpMessageBuf) + + // Send it back + return responsePacket, nil +} From 8f91f0c050ae44188e73efcefb987df54bebb13d Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 13 Jun 2021 05:43:03 -0500 Subject: [PATCH 019/386] fix nodeinfo and debug admin functions, this is ugly / a hack, but it works i guess... --- src/admin/admin.go | 5 +++++ src/core/api.go | 25 +++++++++++++++++++++++++ src/tuntap/admin.go | 4 ---- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/admin/admin.go b/src/admin/admin.go index 7d5c66d1..d41a48e1 100644 --- a/src/admin/admin.go +++ b/src/admin/admin.go @@ -83,6 +83,7 @@ func (a *AdminSocket) Init(c *core.Core, nc *config.NodeConfig, log *log.Logger, } return res, nil }) + a.core.SetAdmin(a) return nil } @@ -142,6 +143,10 @@ func (a *AdminSocket) SetupAdminHandlers(na *AdminSocket) { } return res, nil }) + //_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler) + //_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler) + //_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler) + //_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) } // Start runs the admin API socket to listen for / respond to admin API calls. diff --git a/src/core/api.go b/src/core/api.go index 536b1a87..d1b931cf 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -3,6 +3,7 @@ package core import ( "crypto/ed25519" //"encoding/hex" + "encoding/json" //"errors" //"fmt" "net" @@ -259,3 +260,27 @@ func (c *Core) Close() error { c.Stop() return nil } + +// Hack to get the admin stuff working, TODO something cleaner + +type AddHandler interface { + AddHandler(name string, args []string, handlerfunc func(json.RawMessage) (interface{}, error)) error +} + +// SetAdmin must be called after Init and before Start. +// It sets the admin handler for NodeInfo and the Debug admin functions. +func (c *Core) SetAdmin(a AddHandler) error { + if err := a.AddHandler("getNodeInfo", []string{"key"}, c.proto.nodeinfo.nodeInfoAdminHandler); err != nil { + return err + } + if err := a.AddHandler("debug_remoteGetSelf", []string{"key"}, c.proto.getSelfHandler); err != nil { + return err + } + if err := a.AddHandler("debug_remoteGetPeers", []string{"key"}, c.proto.getPeersHandler); err != nil { + return err + } + if err := a.AddHandler("debug_remoteGetDHT", []string{"key"}, c.proto.getDHTHandler); err != nil { + return err + } + return nil +} diff --git a/src/tuntap/admin.go b/src/tuntap/admin.go index 80b2df00..862a3c66 100644 --- a/src/tuntap/admin.go +++ b/src/tuntap/admin.go @@ -34,8 +34,4 @@ func (t *TunAdapter) SetupAdminHandlers(a *admin.AdminSocket) { } return res, nil }) - //_ = a.AddHandler("getNodeInfo", []string{"key"}, t.proto.nodeinfo.nodeInfoAdminHandler) - //_ = a.AddHandler("debug_remoteGetSelf", []string{"key"}, t.proto.getSelfHandler) - //_ = a.AddHandler("debug_remoteGetPeers", []string{"key"}, t.proto.getPeersHandler) - //_ = a.AddHandler("debug_remoteGetDHT", []string{"key"}, t.proto.getDHTHandler) } From c6a7a077a36a99f852342b2060862c5dae119909 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 13 Jun 2021 09:25:08 -0500 Subject: [PATCH 020/386] add remote URI to GetPeers (fallback to net.Conn.RemoteAddr().String() if the uri is unknown) --- go.mod | 2 +- go.sum | 4 ++-- src/admin/getpeers.go | 2 ++ src/core/api.go | 11 +++++++++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1e27d93b..72a9abc7 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/yggdrasil-network/yggdrasil-go go 1.16 require ( - github.com/Arceliar/ironwood v0.0.0-20210606094153-1bd43ce71198 + github.com/Arceliar/ironwood v0.0.0-20210613142316-e2332dbd4e3f github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 github.com/VividCortex/ewma v1.2.0 // indirect github.com/cheggaaa/pb/v3 v3.0.8 diff --git a/go.sum b/go.sum index dab85269..e7135473 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/Arceliar/ironwood v0.0.0-20210606094153-1bd43ce71198 h1:wLF+CSqm9DrPeT2dp1E4Xe5of8SyUxfJVxw8DHeT1YM= -github.com/Arceliar/ironwood v0.0.0-20210606094153-1bd43ce71198/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= +github.com/Arceliar/ironwood v0.0.0-20210613142316-e2332dbd4e3f h1:fnjzLzu6/0/cyeDVJb9mYS2odsw+6B88D9gO6iRSvGw= +github.com/Arceliar/ironwood v0.0.0-20210613142316-e2332dbd4e3f/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= diff --git a/src/admin/getpeers.go b/src/admin/getpeers.go index 9f53cf23..9ccf9e2f 100644 --- a/src/admin/getpeers.go +++ b/src/admin/getpeers.go @@ -18,6 +18,7 @@ type PeerEntry struct { PublicKey string `json:"key"` Port uint64 `json:"port"` Coords []uint64 `json:"coords"` + Remote string `json:"remote"` } func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersResponse) error { @@ -29,6 +30,7 @@ func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersRespons PublicKey: hex.EncodeToString(p.Key), Port: p.Port, Coords: p.Coords, + Remote: p.Remote, } } return nil diff --git a/src/core/api.go b/src/core/api.go index d1b931cf..0e9d9d7a 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -28,6 +28,7 @@ type Peer struct { Root ed25519.PublicKey Coords []uint64 Port uint64 + Remote string } type DHTEntry struct { @@ -56,6 +57,12 @@ func (c *Core) GetSelf() Self { func (c *Core) GetPeers() []Peer { var peers []Peer + names := make(map[net.Conn]string) + c.links.mutex.Lock() + for _, info := range c.links.links { + names[info.conn] = info.lname + } + c.links.mutex.Unlock() ps := c.pc.PacketConn.Debug.GetPeers() for _, p := range ps { var info Peer @@ -63,6 +70,10 @@ func (c *Core) GetPeers() []Peer { info.Root = p.Root info.Coords = p.Coords info.Port = p.Port + info.Remote = p.Conn.RemoteAddr().String() + if name := names[p.Conn]; name != "" { + info.Remote = name + } peers = append(peers, info) } return peers From 2726dc0076a0e5ceb1c58437c53cc8a4144394e6 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 13 Jun 2021 09:51:53 -0500 Subject: [PATCH 021/386] don't return an error if the source address is wrong, since this happens very frequently for link-local traffic --- src/core/keystore.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/keystore.go b/src/core/keystore.go index d2c6c24a..cdc31aaa 100644 --- a/src/core/keystore.go +++ b/src/core/keystore.go @@ -289,7 +289,9 @@ func (k *keyStore) writePC(bs []byte) (int, error) { copy(srcSubnet[:], bs[8:]) copy(dstSubnet[:], bs[24:]) if srcAddr != k.address && srcSubnet != k.subnet { - return 0, errors.New("wrong source address") + // This happens all the time due to link-local traffic + // Don't send back an error, just drop it + return 0, nil } buf := make([]byte, 1+len(bs), 65535) buf[0] = typeSessionTraffic From da82308d7c306d46a0a9b7ea1e7d80dfcdd8477c Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 13 Jun 2021 10:30:16 -0500 Subject: [PATCH 022/386] update ironwood, fixes bug where sessions could become stuck after a node restarts --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 72a9abc7..6c104b09 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/yggdrasil-network/yggdrasil-go go 1.16 require ( - github.com/Arceliar/ironwood v0.0.0-20210613142316-e2332dbd4e3f + github.com/Arceliar/ironwood v0.0.0-20210613152842-297306b677cc github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 github.com/VividCortex/ewma v1.2.0 // indirect github.com/cheggaaa/pb/v3 v3.0.8 diff --git a/go.sum b/go.sum index e7135473..84c2fad4 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/Arceliar/ironwood v0.0.0-20210613142316-e2332dbd4e3f h1:fnjzLzu6/0/cyeDVJb9mYS2odsw+6B88D9gO6iRSvGw= -github.com/Arceliar/ironwood v0.0.0-20210613142316-e2332dbd4e3f/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= +github.com/Arceliar/ironwood v0.0.0-20210613152842-297306b677cc h1:0eUsfi0FBobUVaBJEcC5x2/Y7Geq7Mpvx51rWmZN7NU= +github.com/Arceliar/ironwood v0.0.0-20210613152842-297306b677cc/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= From 108313153394637fa494f7f0bedccd615e7f3960 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jun 2021 16:52:14 +0100 Subject: [PATCH 023/386] Update build script for Android/iOS --- build | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/build b/build index 66f94403..583bf610 100755 --- a/build +++ b/build @@ -32,18 +32,16 @@ fi 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 \ - github.com/yggdrasil-network/yggdrasil-go/src/config \ + go get golang.org/x/mobile/bind + gomobile bind -target ios -tags mobile -o Yggdrasil.framework -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \ github.com/yggdrasil-network/yggdrasil-extras/src/mobile \ - github.com/yggdrasil-network/yggdrasil-extras/src/dummy + github.com/yggdrasil-network/yggdrasil-go/src/config 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 \ - github.com/yggdrasil-network/yggdrasil-go/src/config \ + go get golang.org/x/mobile/bind + gomobile bind -target android -tags mobile -o yggdrasil.aar -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" \ github.com/yggdrasil-network/yggdrasil-extras/src/mobile \ - github.com/yggdrasil-network/yggdrasil-extras/src/dummy + github.com/yggdrasil-network/yggdrasil-go/src/config else for CMD in yggdrasil yggdrasilctl ; do echo "Building: $CMD" From cb81be94ec15d29d666deb1a56ee6653bf75e5e2 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 13 Jun 2021 12:31:52 -0500 Subject: [PATCH 024/386] skip multicast packets sent from our own key --- src/multicast/multicast.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 6f0e8f98..2b631ca2 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -1,6 +1,7 @@ package multicast import ( + "bytes" "context" "crypto/ed25519" "encoding/hex" @@ -350,6 +351,9 @@ func (m *Multicast) listen() { } var key ed25519.PublicKey key = append(key, bs[:ed25519.PublicKeySize]...) + if bytes.Equal(key, m.core.GetSelf().Key) { + continue // don't bother trying to peer with self + } anAddr := string(bs[ed25519.PublicKeySize:nBytes]) addr, err := net.ResolveTCPAddr("tcp6", anAddr) if err != nil { From b34c3230f877a3b6fd0101e2c362d3fda7874037 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 13 Jun 2021 13:40:20 -0500 Subject: [PATCH 025/386] fix core_test.go and a race in setting/using mtu --- src/core/api.go | 8 ++++++-- src/core/core_test.go | 31 ++++++++++++++++++++++--------- src/core/keystore.go | 7 +++++-- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/core/api.go b/src/core/api.go index 0e9d9d7a..05d9f36f 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -243,16 +243,20 @@ func (c *Core) MaxMTU() uint64 { return c.store.maxSessionMTU() } -// SetMTU can only safely be called after Init and before Start. func (c *Core) SetMTU(mtu uint64) { if mtu < 1280 { mtu = 1280 } + c.store.mutex.Lock() c.store.mtu = mtu + c.store.mutex.Unlock() } func (c *Core) MTU() uint64 { - return c.store.mtu + c.store.mutex.Lock() + mtu := c.store.mtu + c.store.mutex.Unlock() + return mtu } // Implement io.ReadWriteCloser diff --git a/src/core/core_test.go b/src/core/core_test.go index 7e7f32d1..9a2f230f 100644 --- a/src/core/core_test.go +++ b/src/core/core_test.go @@ -43,11 +43,13 @@ func CreateAndConnectTwo(t testing.TB, verbose bool) (nodeA *Core, nodeB *Core) if err := nodeA.Start(GenerateConfig(), GetLoggerWithPrefix("A: ", verbose)); err != nil { t.Fatal(err) } + nodeA.SetMTU(1500) nodeB = new(Core) if err := nodeB.Start(GenerateConfig(), GetLoggerWithPrefix("B: ", verbose)); err != nil { t.Fatal(err) } + nodeB.SetMTU(1500) u, err := url.Parse("tcp://" + nodeA.links.tcp.getAddr().String()) if err != nil { @@ -89,8 +91,9 @@ func CreateEchoListener(t testing.TB, nodeA *Core, bufLen int, repeats int) chan done := make(chan struct{}) go func() { buf := make([]byte, bufLen) + res := make([]byte, bufLen) for i := 0; i < repeats; i++ { - n, from, err := nodeA.ReadFrom(buf) + n, err := nodeA.Read(buf) if err != nil { t.Error(err) return @@ -99,7 +102,10 @@ func CreateEchoListener(t testing.TB, nodeA *Core, bufLen int, repeats int) chan t.Error("missing data") return } - _, err = nodeA.WriteTo(buf, from) + copy(res, buf) + copy(res[8:24], buf[24:40]) + copy(res[24:40], buf[8:24]) + _, err = nodeA.Write(res) if err != nil { t.Error(err) } @@ -130,17 +136,20 @@ func TestCore_Start_Transfer(t *testing.T) { // Send msg := make([]byte, msgLen) - rand.Read(msg) - _, err := nodeB.WriteTo(msg, nodeA.LocalAddr()) + rand.Read(msg[40:]) + msg[0] = 0x60 + copy(msg[8:24], nodeB.Address()) + copy(msg[24:40], nodeA.Address()) + _, err := nodeB.Write(msg) if err != nil { t.Fatal(err) } buf := make([]byte, msgLen) - _, _, err = nodeB.ReadFrom(buf) + _, err = nodeB.Read(buf) if err != nil { t.Fatal(err) } - if !bytes.Equal(msg, buf) { + if !bytes.Equal(msg[40:], buf[40:]) { t.Fatal("expected echo") } <-done @@ -159,18 +168,22 @@ func BenchmarkCore_Start_Transfer(b *testing.B) { // Send msg := make([]byte, msgLen) - rand.Read(msg) + rand.Read(msg[40:]) + msg[0] = 0x60 + copy(msg[8:24], nodeB.Address()) + copy(msg[24:40], nodeA.Address()) + buf := make([]byte, msgLen) b.SetBytes(int64(msgLen)) b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := nodeB.WriteTo(msg, nodeA.LocalAddr()) + _, err := nodeB.Write(msg) if err != nil { b.Fatal(err) } - _, _, err = nodeB.ReadFrom(buf) + _, err = nodeB.Read(buf) if err != nil { b.Fatal(err) } diff --git a/src/core/keystore.go b/src/core/keystore.go index cdc31aaa..82fa9317 100644 --- a/src/core/keystore.go +++ b/src/core/keystore.go @@ -243,12 +243,15 @@ func (k *keyStore) readPC(p []byte) (int, error) { if len(bs) < 40 { continue } - if len(bs) > int(k.mtu) { + k.mutex.Lock() + mtu := int(k.mtu) + k.mutex.Unlock() + if len(bs) > mtu { // Using bs would make it leak off the stack, so copy to buf buf := make([]byte, 40) copy(buf, bs) ptb := &icmp.PacketTooBig{ - MTU: int(k.mtu), + MTU: mtu, Data: buf[:40], } if packet, err := CreateICMPv6(buf[8:24], buf[24:40], ipv6.ICMPTypePacketTooBig, 0, ptb); err == nil { From 1bf751a4746de8aa90e3a111ec46a20ef671b06a Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 19 Jun 2021 07:44:37 -0500 Subject: [PATCH 026/386] update ironwood, only store 1 packet in the pre-session buffer --- go.mod | 2 +- go.sum | 4 ++-- src/core/keystore.go | 14 +++++--------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 6c104b09..398504cb 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/yggdrasil-network/yggdrasil-go go 1.16 require ( - github.com/Arceliar/ironwood v0.0.0-20210613152842-297306b677cc + github.com/Arceliar/ironwood v0.0.0-20210619124114-6ad55cae5031 github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 github.com/VividCortex/ewma v1.2.0 // indirect github.com/cheggaaa/pb/v3 v3.0.8 diff --git a/go.sum b/go.sum index 84c2fad4..5d11fad6 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/Arceliar/ironwood v0.0.0-20210613152842-297306b677cc h1:0eUsfi0FBobUVaBJEcC5x2/Y7Geq7Mpvx51rWmZN7NU= -github.com/Arceliar/ironwood v0.0.0-20210613152842-297306b677cc/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= +github.com/Arceliar/ironwood v0.0.0-20210619124114-6ad55cae5031 h1:DZVDfYhVdu+0wAiRHoY1olyNkKxIot9UjBnbQFzuUlM= +github.com/Arceliar/ironwood v0.0.0-20210619124114-6ad55cae5031/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= diff --git a/src/core/keystore.go b/src/core/keystore.go index 82fa9317..5062a675 100644 --- a/src/core/keystore.go +++ b/src/core/keystore.go @@ -40,7 +40,7 @@ type keyInfo struct { } type buffer struct { - packets [][]byte + packet []byte timeout *time.Timer } @@ -73,7 +73,7 @@ func (k *keyStore) sendToAddress(addr address.Address, bs []byte) { k.addrBuffer[addr] = buf } msg := append([]byte(nil), bs...) - buf.packets = append(buf.packets, msg) + buf.packet = msg if buf.timeout != nil { buf.timeout.Stop() } @@ -102,7 +102,7 @@ func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { k.subnetBuffer[subnet] = buf } msg := append([]byte(nil), bs...) - buf.packets = append(buf.packets, msg) + buf.packet = msg if buf.timeout != nil { buf.timeout.Stop() } @@ -134,15 +134,11 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.resetTimeout(info) k.mutex.Unlock() if buf := k.addrBuffer[info.address]; buf != nil { - for _, bs := range buf.packets { - _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) - } + k.core.pc.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.addrBuffer, info.address) } if buf := k.subnetBuffer[info.subnet]; buf != nil { - for _, bs := range buf.packets { - _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) - } + k.core.pc.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.subnetBuffer, info.subnet) } } else { From 5564de94ba7b54005bda5e572359ee0db45d6ae6 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 19 Jun 2021 09:53:11 -0500 Subject: [PATCH 027/386] when using tls, if no pinned key is set, pin the key from the cert. require that cert keys match a pinned key --- src/core/tcp.go | 4 ++-- src/core/tls.go | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/core/tcp.go b/src/core/tcp.go index 5c3e506b..4dc36a08 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -54,7 +54,7 @@ type TcpListener struct { } type TcpUpgrade struct { - upgrade func(c net.Conn) (net.Conn, error) + upgrade func(c net.Conn, o *tcpOptions) (net.Conn, error) name string } @@ -361,7 +361,7 @@ func (t *tcp) handler(sock net.Conn, incoming bool, options tcpOptions) chan str var upgraded bool if options.upgrade != nil { var err error - if sock, err = options.upgrade.upgrade(sock); err != nil { + if sock, err = options.upgrade.upgrade(sock, &options); err != nil { t.links.core.log.Errorln("TCP handler upgrade failed:", err) return nil } diff --git a/src/core/tls.go b/src/core/tls.go index 4fdcf997..4c25225b 100644 --- a/src/core/tls.go +++ b/src/core/tls.go @@ -9,6 +9,7 @@ import ( "crypto/x509/pkix" "encoding/hex" "encoding/pem" + "errors" "log" "math/big" "net" @@ -76,16 +77,47 @@ func (t *tcptls) init(tcp *tcp) { } } -func (t *tcptls) upgradeListener(c net.Conn) (net.Conn, error) { - conn := tls.Server(c, t.config) +func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { + config := *t.config + config.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error { + if len(rawCerts) != 1 { + return errors.New("tls not exactly 1 cert") + } + cert, err := x509.ParseCertificate(rawCerts[0]) + if err != nil { + return errors.New("tls failed to parse cert") + } + if cert.PublicKeyAlgorithm != x509.Ed25519 { + return errors.New("tls wrong cert algorithm") + } + pk := cert.PublicKey.(ed25519.PublicKey) + var key keyArray + copy(key[:], pk) + // If options does not have a pinned key, then pin one now + if options.pinnedEd25519Keys == nil { + options.pinnedEd25519Keys = make(map[keyArray]struct{}) + options.pinnedEd25519Keys[key] = struct{}{} + } + if _, isIn := options.pinnedEd25519Keys[key]; !isIn { + return errors.New("tls key does not match pinned key") + } + return nil + } + return &config +} + +func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, error) { + config := t.configForOptions(options) + conn := tls.Server(c, config) if err := conn.Handshake(); err != nil { return c, err } return conn, nil } -func (t *tcptls) upgradeDialer(c net.Conn) (net.Conn, error) { - conn := tls.Client(c, t.config) +func (t *tcptls) upgradeDialer(c net.Conn, options *tcpOptions) (net.Conn, error) { + config := t.configForOptions(options) + conn := tls.Client(c, config) if err := conn.Handshake(); err != nil { return c, err } From b7f57c0617478b521e81c488abddced2ea12d13f Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 19 Jun 2021 10:42:38 -0500 Subject: [PATCH 028/386] use TLS for multicast peers, fix TLS listener type in log output --- src/core/tcp.go | 8 ++++++-- src/multicast/multicast.go | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/core/tcp.go b/src/core/tcp.go index 4dc36a08..572fd652 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -185,17 +185,21 @@ func (t *tcp) listener(l *TcpListener, listenaddr string) { l.Listener.Close() return } + callproto := "TCP" + if l.opts.upgrade != nil { + callproto = strings.ToUpper(l.opts.upgrade.name) + } t.listeners[listenaddr] = l t.mutex.Unlock() // And here we go! defer func() { - t.links.core.log.Infoln("Stopping TCP listener on:", l.Listener.Addr().String()) + t.links.core.log.Infoln("Stopping", callproto, "listener on:", l.Listener.Addr().String()) l.Listener.Close() t.mutex.Lock() delete(t.listeners, listenaddr) t.mutex.Unlock() }() - t.links.core.log.Infoln("Listening for TCP on:", l.Listener.Addr().String()) + t.links.core.log.Infoln("Listening for", callproto, "on:", l.Listener.Addr().String()) go func() { <-l.stop l.Listener.Close() diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 2b631ca2..ef564bb3 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -277,7 +277,7 @@ func (m *Multicast) _announce() { var info *listenerInfo if nfo, ok := m.listeners[iface.Name]; !ok || nfo.listener.Listener == nil { // No listener was found - let's create one - urlString := fmt.Sprintf("tcp://[%s]:%d", addrIP, m.listenPort) + urlString := fmt.Sprintf("tls://[%s]:%d", addrIP, m.listenPort) u, err := url.Parse(urlString) if err != nil { panic(err) @@ -370,7 +370,7 @@ func (m *Multicast) listen() { if _, ok := interfaces[from.Zone]; ok { addr.Zone = "" pin := fmt.Sprintf("/?key=%s", hex.EncodeToString(key)) - u, err := url.Parse("tcp://" + addr.String() + pin) + u, err := url.Parse("tls://" + addr.String() + pin) if err != nil { m.log.Debugln("Call from multicast failed, parse error:", addr.String(), err) } From 39361af7892d5ccd8c567068bd46b5c17f2fa817 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 19 Jun 2021 17:51:11 +0100 Subject: [PATCH 029/386] Update config comments --- go.mod | 1 + go.sum | 28 ++++++++++++++++++++++++++++ src/config/config.go | 12 ++++++------ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 398504cb..844dfaee 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect + github.com/yggdrasil-network/yggdrasil-extras v0.0.0-20210616080244-468e4a33c3f6 // indirect golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect golang.org/x/net v0.0.0-20210610132358-84b48f89b13b golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 diff --git a/go.sum b/go.sum index 5d11fad6..1fde4fd1 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,9 @@ +github.com/Arceliar/ironwood v0.0.0-20210613152842-297306b677cc/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/ironwood v0.0.0-20210619124114-6ad55cae5031 h1:DZVDfYhVdu+0wAiRHoY1olyNkKxIot9UjBnbQFzuUlM= github.com/Arceliar/ironwood v0.0.0-20210619124114-6ad55cae5031/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= @@ -38,18 +40,37 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/yggdrasil-network/yggdrasil-extras v0.0.0-20210616080244-468e4a33c3f6 h1:bwgqxLteeI2ruLUrVVSuIfYJY4vUno8Zne1unV9iLls= +github.com/yggdrasil-network/yggdrasil-extras v0.0.0-20210616080244-468e4a33c3f6/go.mod h1:+4d9w7U71su9wXzpOxwtxRmXgjnwpJjQpX6vi2rwpv4= +github.com/yggdrasil-network/yggdrasil-go v0.3.17-0.20210613153016-da82308d7c30/go.mod h1:ELFERsaKIevEZRjoynRDiovh06EZUCAhTAkZHkEGRIE= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20210527171505-7e972142eb43/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -59,6 +80,7 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -72,6 +94,12 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 h1:wfOOSvHgIzTZ9h5Vb6yUFZNn7uf3bT7PeYsHOO7tYDM= golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= diff --git a/src/config/config.go b/src/config/config.go index fa110122..934c4091 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -29,14 +29,14 @@ import ( // supply one of these structs to the Yggdrasil core when starting a node. type NodeConfig struct { sync.RWMutex `json:"-"` - Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."` - InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tcp://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."` - Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntcp://0.0.0.0:0 or tcp://[::]:0 to listen on all interfaces."` + Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tls://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."` + InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tls://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."` + Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntls://0.0.0.0:0 or tls://[::]:0 to listen on all interfaces."` AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."` MulticastInterfaces []string `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."` - AllowedPublicKeys []string `comment:"List of peer encryption public keys to allow incoming TCP peering\nconnections from. If left empty/undefined then all connections will\nbe allowed by default. This does not affect outgoing peerings, nor\ndoes it affect link-local peers discovered via multicast."` - PublicKey string `comment:"Your public signing key. Your peers may ask you for this to put\ninto their AllowedPublicKeys configuration."` - PrivateKey string `comment:"Your private signing key. DO NOT share this with anyone!"` + AllowedPublicKeys []string `comment:"List of peer public keys to allow incoming peering connections\nfrom. If left empty/undefined then all connections will be allowed\nby default. This does not affect outgoing peerings, nor does it\naffect link-local peers discovered via multicast."` + PublicKey string `comment:"Your public key. Your peers may ask you for this to put\ninto their AllowedPublicKeys configuration."` + PrivateKey string `comment:"Your private key. DO NOT share this with anyone!"` LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."` IfName string `comment:"Local network interface name for TUN adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN."` IfMTU uint64 `comment:"Maximum Transmission Unit (MTU) size for your local TUN interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` From 9b9ef2fad740df5b4c0d57eefd39b06ae51ae397 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 19 Jun 2021 11:56:03 -0500 Subject: [PATCH 030/386] tidy --- go.mod | 1 - go.sum | 28 ---------------------------- 2 files changed, 29 deletions(-) diff --git a/go.mod b/go.mod index 844dfaee..398504cb 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,6 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect - github.com/yggdrasil-network/yggdrasil-extras v0.0.0-20210616080244-468e4a33c3f6 // indirect golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect golang.org/x/net v0.0.0-20210610132358-84b48f89b13b golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 diff --git a/go.sum b/go.sum index 1fde4fd1..5d11fad6 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ -github.com/Arceliar/ironwood v0.0.0-20210613152842-297306b677cc/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/ironwood v0.0.0-20210619124114-6ad55cae5031 h1:DZVDfYhVdu+0wAiRHoY1olyNkKxIot9UjBnbQFzuUlM= github.com/Arceliar/ironwood v0.0.0-20210619124114-6ad55cae5031/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ= github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= @@ -40,37 +38,18 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/yggdrasil-network/yggdrasil-extras v0.0.0-20210616080244-468e4a33c3f6 h1:bwgqxLteeI2ruLUrVVSuIfYJY4vUno8Zne1unV9iLls= -github.com/yggdrasil-network/yggdrasil-extras v0.0.0-20210616080244-468e4a33c3f6/go.mod h1:+4d9w7U71su9wXzpOxwtxRmXgjnwpJjQpX6vi2rwpv4= -github.com/yggdrasil-network/yggdrasil-go v0.3.17-0.20210613153016-da82308d7c30/go.mod h1:ELFERsaKIevEZRjoynRDiovh06EZUCAhTAkZHkEGRIE= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20210527171505-7e972142eb43/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -80,7 +59,6 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -94,12 +72,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 h1:wfOOSvHgIzTZ9h5Vb6yUFZNn7uf3bT7PeYsHOO7tYDM= golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= From 50bd16d524e3dd8ef565a8ea6ffec94473fbec8f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 19 Jun 2021 18:02:38 +0100 Subject: [PATCH 031/386] Remove doc folder, out of date --- .gitmodules | 3 - doc/Whitepaper.md | 148 -------------------------------- doc/yggdrasil-network.github.io | 1 - 3 files changed, 152 deletions(-) delete mode 100644 .gitmodules delete mode 100644 doc/Whitepaper.md delete mode 160000 doc/yggdrasil-network.github.io diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e4e8b525..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "doc/yggdrasil-network.github.io"] - path = doc/yggdrasil-network.github.io - url = https://github.com/yggdrasil-network/yggdrasil-network.github.io/ diff --git a/doc/Whitepaper.md b/doc/Whitepaper.md deleted file mode 100644 index b65963d1..00000000 --- a/doc/Whitepaper.md +++ /dev/null @@ -1,148 +0,0 @@ -# Yggdrasil - -Note: This is a very rough early draft. - -Yggdrasil is an encrypted IPv6 network running in the [`200::/7` address range](https://en.wikipedia.org/wiki/Unique_local_address). -It is an experimental/toy network, so failure is acceptable, as long as it's instructive to see how it breaks if/when everything falls apart. - -IP addresses are derived from cryptographic keys, to reduce the need for public key infrastructure. -A form of locator/identifier separation (similar in goal to [LISP](https://en.wikipedia.org/wiki/Locator/Identifier_Separation_Protocol)) is used to map static identifiers (IP addresses) onto dynamic routing information (locators), using a [distributed hash table](https://en.wikipedia.org/wiki/Distributed_hash_table) (DHT). -Locators are used to approximate the distance between nodes in the network, where the approximate distance is the length of a real worst-case-scenario path through the network. -This is (arguably) easier to secure and requires less information about the network than commonly used routing schemes. - -While not technically a [compact routing scheme](https://arxiv.org/abs/0708.2309), tests on real-world networks suggest that routing in this style incurs stretch comparable to the name-dependent compact routing schemes designed for static networks. -Compared to compact routing schemes, Yggdrasil appears to have smaller average routing table sizes, works on dynamic networks, and is name-independent. -It currently lacks the provable bounds of compact routing schemes, and there's a serious argument to be made that it cheats by stretching the definition of some of the above terms, but the main point to be emphasized is that there are trade-offs between different concerns when trying to route traffic, and we'd rather make every part *good* than try to make any one part *perfect*. -In that sense, Yggdrasil seems to be competitive, on what are supposedly realistic networks, with compact routing schemes. - -## Addressing - -Yggdrasil uses a truncated version of a `NodeID` to assign addresses. -An address is assigned from the `200::/7` prefix, according to the following: - -1. Begin with `0x02` as the first byte of the address, or `0x03` if it's a `/64` prefix. -2. Count the number of leading `1` bits in the NodeID. -3. Set the second byte of the address to the number of leading `1` bits in the NodeID (8 bit unsigned integer, at most 255). -4. Append the NodeID to the remaining bits of the address, truncating the leading `1` bits and the first `0` bit, to a total address size of 128 bits. - -The last bit of the first byte is used to flag if an address is for a router (`200::/8`), or part of an advertised prefix (`300::/8`), where each router owns a `/64` that matches their address (except with the eight bit set to 1 instead of 0). -This allows the prefix to be advertised to the router's LAN, so unsupported devices can still connect to the network (e.g. network printers). - -The NodeID is a [sha512sum](https://en.wikipedia.org/wiki/SHA-512) of a node's public encryption key. -Addresses are checked that they match NodeID, to prevent address spoofing. -As such, while a 128 bit IPv6 address is likely too short to be considered secure by cryptographer standards, there is a significant cost in attempting to cause an address collision. -Addresses can be made more secure by brute force generating a large number of leading `1` bits in the NodeID. - -When connecting to a node, the IP address is unpacked into the known bits of the NodeID and a matching bitmask to track which bits are significant. -A node is only communicated with if its `NodeID` matches its public key and the known `NodeID` bits from the address. - -It is important to note that only `NodeID` is used internally for routing, so the addressing scheme could in theory be changed without breaking compatibility with intermediate routers. -This has been done once, when moving the address range from the `fd00::/8` ULA range to the reserved-but-[deprecated](https://tools.ietf.org/html/rfc4048) `200::/7` range. -Further addressing scheme changes could occur if, for example, an IPv7 format ever emerges. - -### Cryptography - -Public key encryption is done using the `golang.org/x/crypto/nacl/box`, which uses [Curve25519](https://en.wikipedia.org/wiki/Curve25519), [XSalsa20](https://en.wikipedia.org/wiki/Salsa20), and [Poly1305](https://en.wikipedia.org/wiki/Poly1305) for key exchange, encryption, and authentication (interoperable with [NaCl](https://en.wikipedia.org/wiki/NaCl_(software))). -Permanent keys are used only for protocol traffic, with random nonces generated on a per-packet basis using `crypto/rand` from Go's standard library. -Ephemeral session keys (for [forward secrecy](https://en.wikipedia.org/wiki/Forward_secrecy)) are generated for encapsulated IPv6 traffic, using the same set of primitives, with random initial nonces that are subsequently incremented. -A list of recently received session nonces is kept (as a bitmask) and checked to reject duplicated packets, in an effort to block duplicate packets and replay attacks. -A separate set of keys are generated and used for signing with [Ed25519](https://en.wikipedia.org/wiki/Ed25519), which is used by the routing layer to secure construction of a spanning tree. - -### Prefixes - -Recall that each node's address is in the lower half of the address range, I.e. `200::/8`. A `/64` prefix is made available to each node under `300::/8`, where the remaining bits of the prefix match the node's address under `200::/8`. -A node may optionally advertise a prefix on their local area network, which allows unsupported or legacy devices with IPv6 support to connect to the network. -Note that there are 64 fewer bits of `NodeID` available to check in each address from a routing prefix, so it makes sense to brute force a `NodeID` with more significant bits in the address if this approach is to be used. -Running `genkeys.go` will do this by default. - -## Locators and Routing - -Locators are generated using information from a spanning tree (described below). -The result is that each node has a set of [coordinates in a greedy metric space](https://en.wikipedia.org/wiki/Greedy_embedding). -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 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 embedded 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). -If no non-empty queue is available, then the peer is added to the idle set, forward packets when the need arises. - -This acts as a crude approximation of backpressure routing, where the remote queue sizes are assumed to be equal to the distance of a node from a destination (rather than communicating queue size information), and packets are never forwarded "backwards" through the network, but congestion on a local link is routed around when possible. -The queue selection strategy behaves similar to shortest-queue-first, in that a larger fraction of available bandwidth to sessions that attempt to use less bandwidth, and is loosely based on the rationale behind some proposed solutions to the [cake-cutting](https://en.wikipedia.org/wiki/Fair_cake-cutting) problem. - -The queue size is limited to 4 MB. If a packet is added to a queue and the total size of all queues is larger than this threshold, then a random queue is selected (with odds proportional to relative queue sizes), and the first packet from that queue is dropped, with the process repeated until the total queue size drops below the allowed threshold. - -Note that this forwarding procedure generalizes to nodes that are not one-hop neighbors, but the current implementation omits the use of more distant neighbors, as this is expected to be a minor optimization (it would add per-link control traffic to pass path-vector-like information about a subset of the network, which is a lot of overhead compared to the current setup). - -### Spanning Tree - -A [spanning tree](https://en.wikipedia.org/wiki/Spanning_tree) is constructed with the tree rooted at the highest TreeID, where TreeID is equal to a sha512sum of a node's public [Ed25519](https://en.wikipedia.org/wiki/Ed25519) key (used for signing). -A node sends periodic advertisement messages to each neighbor. -The advertisement contains the coords that match the path from the root through the node, plus one additional hop from the node to the neighbor being advertised to. -Each hop in this advertisement includes a matching ed25519 signature. -These signatures prevent nodes from forging arbitrary routing advertisements. - -The first hop, from the root, also includes a sequence number, which must be updated periodically. -A node will blacklist the current root (keeping a record of the last sequence number observed) if the root fails to update for longer than some timeout (currently hard coded at 1 minute). -Normally, a root node will update their sequence number for frequently than this (once every 30 seconds). -Nodes are throttled to ignore updates with a new sequence number for some period after updating their most recently seen sequence number (currently this cooldown is 15 seconds). -The implementation chooses to set the sequence number equal to the unix time on the root's clock, so that a new (higher) sequence number will be selected if the root is restarted and the clock is not set back. - -Other than the root node, every other node in the network must select one of its neighbors to use as their parent. -This selection is done by tracking when each neighbor first sends us a message with a new timestamp from the root, to determine the ordering of the latency of each path from the root, to each neighbor, and then to the node that's searching for a parent. -These relative latencies are tracked by, for each neighbor, keeping a score vs each other neighbor. -If a neighbor sends a message with an updated timestamp before another neighbor, then the faster neighbor's score is increased by 1. -If the neighbor sends a message slower, then the score is decreased by 2, to make sure that a node must be reliably faster (at least 2/3 of the time) to see a net score increase over time. -If a node begins to advertise new coordinates, then its score vs all other nodes is reset to 0. -A node switches to a new parent if a neighbor's score (vs the current parent) reaches some threshold, currently 240, which corresponds to about 2 hours of being a reliably faster path. -The intended outcome of this process is that stable connections from fixed infrastructure near the "core" of the network should (eventually) select parents that minimize latency from the root to themselves, while the more dynamic parts of the network, presumably more towards the edges, will try to favor reliability when selecting a parent. - -The distance metric between nodes is simply the distance between the nodes if they routed on the spanning tree. -This is equal to the sum of the distance from each node to the last common ancestor of the two nodes being compared. -The locator then consists of a root's key, timestamp, and coordinates representing each hop in the path from the root to the node. -In practice, only the coords are used for routing, while the root and timestamp, along with all the per-hop signatures, are needed to securely construct the spanning tree. - -## Name-independent routing - -A [Chord](https://en.wikipedia.org/wiki/Chord_(peer-to-peer))-like Distributed Hash Table (DHT) is used as a distributed database that maps NodeIDs onto coordinates in the spanning tree metric space. -The DHT is Chord-like in that it uses a successor/predecessor structure to do lookups in `O(n)` time with `O(1)` entries, then augments this with some additional information, adding roughly `O(logn)` additional entries, to reduce the lookup time to something around `O(logn)`. -In the long term, the idea is to favor spending our bandwidth making sure the minimum `O(1)` part is right, to prioritize correctness, and then try to conserve bandwidth (and power) by being a bit lazy about checking the remaining `O(logn)` portion when it's not in use. - -To be specific, the DHT stores the immediate successor of a node, plus the next node it manages to find which is strictly closer (by the tree hop-count metric) than all previous nodes. -The same process is repeated for predecessor nodes, and lookups walk the network in the predecessor direction, with each key being owned by its successor (to make sure defaulting to 0 for unknown bits of a `NodeID` doesn't cause us to overshoot the target during a lookup). -In addition, all of a node's one-hop neighbors are included in the DHT, since we get this information "for free", and we must include it in our DHT to ensure that the network doesn't diverge to a broken state (though I suspect that only adding parents or parent-child relationships may be sufficient -- worth trying to prove or disprove, if somebody's bored). -The DHT differs from Chord in that there are no values in the key:value store -- it only stores information about DHT peers -- and that it uses a [Kademlia](https://en.wikipedia.org/wiki/Kademlia)-inspired iterative-parallel lookup process. - -To summarize the entire routing procedure, when given only a node's IP address, the goal is to find a route to the destination. -That happens through 3 steps: - -1. The address is unpacked into the known bits of a NodeID and a bitmask to signal which bits of the NodeID are known (the unknown bits are ignored). -2. A DHT search is performed, which normally results in a response from the node closest in the DHT keyspace to the target `NodeID`. The response contains the node's curve25519 public key, which is checked to match the `NodeID` (and therefore the address), as well as the node's coordinates. -3. Using the keys and coords from the above step, an ephemeral key exchange occurs between the source and destination nodes. These ephemeral session keys are used to encrypt any ordinary IPv6 traffic that may be encapsulated and sent between the nodes. - -From that point, the session keys and coords are cached and used to encrypt and send traffic between nodes. This is *mostly* transparent to the user: the initial DHT lookup and key exchange takes at least 2 round trips, so there's some delay before session setup completes and normal IPv6 traffic can flow. This is similar to the delay caused by a DNS lookup, although it generally takes longer, as a DHT lookup requires multiple iterations to reach the destination. - -## Project Status and Plans - -The current (Go) implementation is considered alpha, so compatibility with future versions is neither guaranteed nor expected. -While users are discouraged from running anything truly critical on top of it, as of writing, it seems reliable enough for day-to-day use. - -As an "alpha" quality release, Yggdrasil *should* at least be able to detect incompatible versions when it sees them, and warn the users that an update may be needed. -A "beta" quality release should know enough to be compatible in the face of wire format changes, and reasonably feature complete. -A "stable" 1.0 release, if it ever happens, would probably be feature complete, with no expectation of future wire format changes, and free of known critical bugs. - -Roughly speaking, there are a few obvious ways the project could turn out: - -1. The developers could lose interest before it goes anywhere. -2. The project could be reasonably complete (beta or stable), but never gain a significant number of users. -3. The network may grow large enough that fundamental (non-fixable) design problems appear, which is hopefully a learning experience, but the project may die as a result. -4. The network may grow large, but never hit any design problems, in which case we need to think about either moving the important parts into other projects ([cjdns](https://github.com/cjdelisle/cjdns)) or rewriting compatible implementations that are better optimized for the target platforms (e.g. a linux kernel module). - -That last one is probably impossible, because the speed of light would *eventually* become a problem, for a sufficiently large network. -If the only thing limiting network growth turns out to be the underlying physics, then that arguably counts as a win. - -Also, note that some design decisions were made for ease-of-programming or ease-of-testing reasons, and likely need to be reconsidered at some point. -In particular, Yggdrasil currently uses TCP for connections with one-hop neighbors, which introduces an additional layer of buffering that can lead to increased and/or unstable latency in congested areas of the network. - diff --git a/doc/yggdrasil-network.github.io b/doc/yggdrasil-network.github.io deleted file mode 160000 index c876890a..00000000 --- a/doc/yggdrasil-network.github.io +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c876890a51d9140e68d5cec7fbeb2146c2562792 From 3b38ed082fc93b0dcc547bea7c381c19c26838ca Mon Sep 17 00:00:00 2001 From: Arceliar Date: Fri, 25 Jun 2021 21:15:40 -0500 Subject: [PATCH 032/386] make failed sends a debug log, instead of error --- src/core/keystore.go | 6 ++++-- src/tuntap/iface.go | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/keystore.go b/src/core/keystore.go index 5062a675..21fb8459 100644 --- a/src/core/keystore.go +++ b/src/core/keystore.go @@ -4,6 +4,7 @@ import ( "crypto/ed25519" "errors" "fmt" + "net" "sync" "time" @@ -278,7 +279,7 @@ func (k *keyStore) writePC(bs []byte) (int, error) { return 0, errors.New("not an IPv6 packet") // not IPv6 } if len(bs) < 40 { - strErr := fmt.Sprint("undersized IPv6 packet, length:", len(bs)) + strErr := fmt.Sprint("undersized IPv6 packet, length: ", len(bs)) return 0, errors.New(strErr) } var srcAddr, dstAddr address.Address @@ -290,7 +291,8 @@ func (k *keyStore) writePC(bs []byte) (int, error) { if srcAddr != k.address && srcSubnet != k.subnet { // This happens all the time due to link-local traffic // Don't send back an error, just drop it - return 0, nil + strErr := fmt.Sprint("incorrect source address: ", net.IP(srcAddr[:]).String()) + return 0, errors.New(strErr) } buf := make([]byte, 1+len(bs), 65535) buf[0] = typeSessionTraffic diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index 587c925e..e72b091f 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -18,7 +18,7 @@ func (tun *TunAdapter) read() { end := begin + n bs := buf[begin:end] if _, err := tun.core.Write(bs); err != nil { - tun.log.Errorln("Unable to send packet:", err) + tun.log.Debugln("Unable to send packet:", err) } } } From d1dfe38683b354f15cb1b5c5c76fad4f43c89fed Mon Sep 17 00:00:00 2001 From: Arceliar Date: Fri, 25 Jun 2021 21:27:29 -0500 Subject: [PATCH 033/386] remove string from multicast announcement format --- src/multicast/multicast.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index ef564bb3..5d9f689c 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/ed25519" + "encoding/binary" "encoding/hex" "fmt" "net" @@ -307,7 +308,10 @@ func (m *Multicast) _announce() { a.Zone = "" destAddr.Zone = iface.Name msg := append([]byte(nil), m.core.GetSelf().Key...) - msg = append(msg, a.String()...) + msg = append(msg, a.IP...) + pbs := make([]byte, 2) + binary.BigEndian.PutUint16(pbs, uint16(a.Port)) + msg = append(msg, pbs...) _, _ = m.sock.WriteTo(msg, nil, destAddr) } if info.interval.Seconds() < 15 { @@ -354,13 +358,20 @@ func (m *Multicast) listen() { if bytes.Equal(key, m.core.GetSelf().Key) { continue // don't bother trying to peer with self } - anAddr := string(bs[ed25519.PublicKeySize:nBytes]) - addr, err := net.ResolveTCPAddr("tcp6", anAddr) + begin := ed25519.PublicKeySize + end := nBytes - 2 + if end <= begin { + continue // malformed address + } + ip := bs[begin:end] + port := binary.BigEndian.Uint16(bs[end:nBytes]) + anAddr := net.TCPAddr{IP: ip, Port: int(port)} + addr, err := net.ResolveTCPAddr("tcp6", anAddr.String()) if err != nil { continue } from := fromAddr.(*net.UDPAddr) - if addr.IP.String() != from.IP.String() { + if !from.IP.Equal(addr.IP) { continue } var interfaces map[string]interfaceInfo From 2db46c1250c8f1f8add58a75dab35adcbd966c7a Mon Sep 17 00:00:00 2001 From: Arceliar Date: Fri, 25 Jun 2021 21:40:19 -0500 Subject: [PATCH 034/386] make socks connect to tls listeners, TODO make that configurable --- src/core/link.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/link.go b/src/core/link.go index 295a8ad6..165b18b2 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -93,6 +93,7 @@ func (l *links) call(u *url.URL, sintf string) error { tcpOpts.socksProxyAuth.User = u.User.Username() tcpOpts.socksProxyAuth.Password, _ = u.User.Password() } + tcpOpts.upgrade = l.tcp.tls.forDialer // TODO make this configurable pathtokens := strings.Split(strings.Trim(u.Path, "/"), "/") l.tcp.call(pathtokens[0], tcpOpts, sintf) case "tls": From 2a7a53b6b6a826a81a49283b420a575416fc3084 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 27 Jun 2021 02:18:51 -0500 Subject: [PATCH 035/386] move GenerateConfig to defaults, to adjust dependency ordering, needed for stuff later --- cmd/yggdrasil/main.go | 7 ++++--- src/config/config.go | 28 ---------------------------- src/defaults/defaults.go | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 114e37f3..79c243ba 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -25,6 +25,7 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/admin" "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/defaults" "github.com/yggdrasil-network/yggdrasil-go/src/core" "github.com/yggdrasil-network/yggdrasil-go/src/multicast" @@ -73,7 +74,7 @@ func readConfig(log *log.Logger, useconf *bool, useconffile *string, normaliseco // 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 := config.GenerateConfig() + cfg := defaults.GenerateConfig() var dat map[string]interface{} if err := hjson.Unmarshal(conf, &dat); err != nil { panic(err) @@ -114,7 +115,7 @@ func readConfig(log *log.Logger, useconf *bool, useconffile *string, normaliseco // Generates a new configuration and returns it in HJSON format. This is used // with -genconf. func doGenconf(isjson bool) string { - cfg := config.GenerateConfig() + cfg := defaults.GenerateConfig() var bs []byte var err error if isjson { @@ -205,7 +206,7 @@ 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 = config.GenerateConfig() + cfg = defaults.GenerateConfig() case *useconffile != "" || *useconf: // Read the configuration from either stdin or from the filesystem cfg = readConfig(logger, useconf, useconffile, normaliseconf) diff --git a/src/config/config.go b/src/config/config.go index 934c4091..767dc188 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -20,8 +20,6 @@ import ( "crypto/ed25519" "encoding/hex" "sync" - - "github.com/yggdrasil-network/yggdrasil-go/src/defaults" ) // NodeConfig is the main configuration structure, containing configuration @@ -44,32 +42,6 @@ type NodeConfig struct { 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."` } -// Generates default configuration and returns a pointer to the resulting -// NodeConfig. This is used when outputting the -genconf parameter and also when -// using -autoconf. -func GenerateConfig() *NodeConfig { - // Generate encryption keys. - spub, spriv, err := ed25519.GenerateKey(nil) - if err != nil { - panic(err) - } - // Create a node configuration and populate it. - cfg := NodeConfig{} - cfg.Listen = []string{} - cfg.AdminListen = defaults.GetDefaults().DefaultAdminListen - cfg.PublicKey = hex.EncodeToString(spub[:]) - cfg.PrivateKey = hex.EncodeToString(spriv[:]) - cfg.Peers = []string{} - cfg.InterfacePeers = map[string][]string{} - cfg.AllowedPublicKeys = []string{} - cfg.MulticastInterfaces = defaults.GetDefaults().DefaultMulticastInterfaces - cfg.IfName = defaults.GetDefaults().DefaultIfName - cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU - cfg.NodeInfoPrivacy = false - - return &cfg -} - // NewSigningKeys replaces the signing keypair in the NodeConfig with a new // signing keypair. The signing keys are used by the switch to derive the // structure of the spanning tree. diff --git a/src/defaults/defaults.go b/src/defaults/defaults.go index a885c5dd..238a36d7 100644 --- a/src/defaults/defaults.go +++ b/src/defaults/defaults.go @@ -1,5 +1,7 @@ package defaults +import "github.com/yggdrasil-network/yggdrasil-go/src/config" + // Defines which parameters are expected by default for configuration on a // specific platform. These values are populated in the relevant defaults_*.go // for the platform being targeted. They must be set. @@ -18,3 +20,23 @@ type platformDefaultParameters struct { DefaultIfMTU uint64 DefaultIfName string } + +// Generates default configuration and returns a pointer to the resulting +// NodeConfig. This is used when outputting the -genconf parameter and also when +// using -autoconf. +func GenerateConfig() *config.NodeConfig { + // Create a node configuration and populate it. + cfg := new(config.NodeConfig) + cfg.NewKeys() + cfg.Listen = []string{} + cfg.AdminListen = GetDefaults().DefaultAdminListen + cfg.Peers = []string{} + cfg.InterfacePeers = map[string][]string{} + cfg.AllowedPublicKeys = []string{} + cfg.MulticastInterfaces = GetDefaults().DefaultMulticastInterfaces + cfg.IfName = GetDefaults().DefaultIfName + cfg.IfMTU = GetDefaults().DefaultIfMTU + cfg.NodeInfoPrivacy = false + + return cfg +} From 2874ce1327d3c8079a0b1498742aefd3c347de57 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 27 Jun 2021 03:15:41 -0500 Subject: [PATCH 036/386] change multicast config format --- src/config/config.go | 32 +++++++++++-------- src/defaults/defaults.go | 4 ++- src/defaults/defaults_darwin.go | 6 ++-- src/defaults/defaults_freebsd.go | 4 +-- src/defaults/defaults_linux.go | 4 +-- src/defaults/defaults_openbsd.go | 4 +-- src/defaults/defaults_other.go | 4 +-- src/defaults/defaults_windows.go | 4 +-- src/multicast/multicast.go | 53 ++++++++++++++++++++------------ 9 files changed, 68 insertions(+), 47 deletions(-) diff --git a/src/config/config.go b/src/config/config.go index 767dc188..d81907f5 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -27,19 +27,25 @@ import ( // supply one of these structs to the Yggdrasil core when starting a node. type NodeConfig struct { sync.RWMutex `json:"-"` - Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tls://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."` - InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tls://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."` - Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntls://0.0.0.0:0 or tls://[::]:0 to listen on all interfaces."` - AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."` - MulticastInterfaces []string `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."` - AllowedPublicKeys []string `comment:"List of peer public keys to allow incoming peering connections\nfrom. If left empty/undefined then all connections will be allowed\nby default. This does not affect outgoing peerings, nor does it\naffect link-local peers discovered via multicast."` - PublicKey string `comment:"Your public key. Your peers may ask you for this to put\ninto their AllowedPublicKeys configuration."` - PrivateKey string `comment:"Your private key. DO NOT share this with anyone!"` - LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."` - IfName string `comment:"Local network interface name for TUN adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN."` - IfMTU uint64 `comment:"Maximum Transmission Unit (MTU) size for your local TUN interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` - 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."` + Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tls://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."` + InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tls://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."` + Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntls://0.0.0.0:0 or tls://[::]:0 to listen on all interfaces."` + AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."` + MulticastInterfaces []MulticastInterfaceConfig `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."` + AllowedPublicKeys []string `comment:"List of peer public keys to allow incoming peering connections\nfrom. If left empty/undefined then all connections will be allowed\nby default. This does not affect outgoing peerings, nor does it\naffect link-local peers discovered via multicast."` + PublicKey string `comment:"Your public key. Your peers may ask you for this to put\ninto their AllowedPublicKeys configuration."` + PrivateKey string `comment:"Your private key. DO NOT share this with anyone!"` + LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."` + IfName string `comment:"Local network interface name for TUN adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN."` + IfMTU uint64 `comment:"Maximum Transmission Unit (MTU) size for your local TUN interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` + 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."` +} + +type MulticastInterfaceConfig struct { + Regex string + Incoming bool + Outgoing bool } // NewSigningKeys replaces the signing keypair in the NodeConfig with a new diff --git a/src/defaults/defaults.go b/src/defaults/defaults.go index 238a36d7..7912fc76 100644 --- a/src/defaults/defaults.go +++ b/src/defaults/defaults.go @@ -2,6 +2,8 @@ package defaults import "github.com/yggdrasil-network/yggdrasil-go/src/config" +type MulticastInterfaceConfig = config.MulticastInterfaceConfig + // Defines which parameters are expected by default for configuration on a // specific platform. These values are populated in the relevant defaults_*.go // for the platform being targeted. They must be set. @@ -13,7 +15,7 @@ type platformDefaultParameters struct { DefaultConfigFile string // Multicast interfaces - DefaultMulticastInterfaces []string + DefaultMulticastInterfaces []MulticastInterfaceConfig // TUN/TAP MaximumIfMTU uint64 diff --git a/src/defaults/defaults_darwin.go b/src/defaults/defaults_darwin.go index 9fbe6d8e..a21539f7 100644 --- a/src/defaults/defaults_darwin.go +++ b/src/defaults/defaults_darwin.go @@ -13,9 +13,9 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - "en.*", - "bridge.*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: "en.*", Incoming: true, Outgoing: true}, + {Regex: "bridge.*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_freebsd.go b/src/defaults/defaults_freebsd.go index a57be2fa..400ae29a 100644 --- a/src/defaults/defaults_freebsd.go +++ b/src/defaults/defaults_freebsd.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/usr/local/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_linux.go b/src/defaults/defaults_linux.go index 5f3f12a8..ac678d85 100644 --- a/src/defaults/defaults_linux.go +++ b/src/defaults/defaults_linux.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_openbsd.go b/src/defaults/defaults_openbsd.go index 6700eb8f..f3e2376c 100644 --- a/src/defaults/defaults_openbsd.go +++ b/src/defaults/defaults_openbsd.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_other.go b/src/defaults/defaults_other.go index 3b035537..d23c2ef0 100644 --- a/src/defaults/defaults_other.go +++ b/src/defaults/defaults_other.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_windows.go b/src/defaults/defaults_windows.go index 305a2ffe..1e918c3b 100644 --- a/src/defaults/defaults_windows.go +++ b/src/defaults/defaults_windows.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "C:\\Program Files\\Yggdrasil\\yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 5d9f689c..aea4e079 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -38,8 +38,10 @@ type Multicast struct { } type interfaceInfo struct { - iface net.Interface - addrs []net.Addr + iface net.Interface + addrs []net.Addr + incoming bool + outgoing bool } type listenerInfo struct { @@ -136,18 +138,16 @@ func (m *Multicast) _stop() error { } func (m *Multicast) _updateInterfaces() { - interfaces := make(map[string]interfaceInfo) - intfs := m.getAllowedInterfaces() - for _, intf := range intfs { - addrs, err := intf.Addrs() + interfaces := m.getAllowedInterfaces() + for name, info := range interfaces { + addrs, err := info.iface.Addrs() if err != nil { - m.log.Warnf("Failed up get addresses for interface %s: %s", intf.Name, err) + m.log.Warnf("Failed up get addresses for interface %s: %s", name, err) + delete(interfaces, name) continue } - interfaces[intf.Name] = interfaceInfo{ - iface: intf, - addrs: addrs, - } + info.addrs = addrs + interfaces[name] = info } m._interfaces = interfaces } @@ -163,10 +163,10 @@ func (m *Multicast) Interfaces() map[string]net.Interface { } // getAllowedInterfaces returns the currently known/enabled multicast interfaces. -func (m *Multicast) getAllowedInterfaces() map[string]net.Interface { - interfaces := make(map[string]net.Interface) +func (m *Multicast) getAllowedInterfaces() map[string]interfaceInfo { + interfaces := make(map[string]interfaceInfo) // Get interface expressions from config - exprs := m.config.MulticastInterfaces + ifcfgs := m.config.MulticastInterfaces // Ask the system for network interfaces allifaces, err := net.Interfaces() if err != nil { @@ -188,15 +188,23 @@ func (m *Multicast) getAllowedInterfaces() map[string]net.Interface { // Ignore point-to-point interfaces continue } - for _, expr := range exprs { + for _, ifcfg := range ifcfgs { // Compile each regular expression - e, err := regexp.Compile(expr) + e, err := regexp.Compile(ifcfg.Regex) if err != nil { panic(err) } // Does the interface match the regular expression? Store it if so if e.MatchString(iface.Name) { - interfaces[iface.Name] = iface + if ifcfg.Incoming || ifcfg.Outgoing { + info := interfaceInfo{ + iface: iface, + incoming: ifcfg.Incoming, + outgoing: ifcfg.Outgoing, + } + interfaces[iface.Name] = info + } + break } } } @@ -272,8 +280,13 @@ func (m *Multicast) _announce() { if !addrIP.IsLinkLocalUnicast() { continue } - // Join the multicast group - _ = m.sock.JoinGroup(&iface, groupAddr) + if info.outgoing { + // Join the multicast group, so we can listen for advertisements to open outgoing connections + _ = m.sock.JoinGroup(&iface, groupAddr) + } + if !info.incoming { + break // Don't send multicast advertisements if we don't accept incoming connections + } // Try and see if we already have a TCP listener for this interface var info *listenerInfo if nfo, ok := m.listeners[iface.Name]; !ok || nfo.listener.Listener == nil { @@ -378,7 +391,7 @@ func (m *Multicast) listen() { phony.Block(m, func() { interfaces = m._interfaces }) - if _, ok := interfaces[from.Zone]; ok { + if info, ok := interfaces[from.Zone]; ok && info.outgoing { addr.Zone = "" pin := fmt.Sprintf("/?key=%s", hex.EncodeToString(key)) u, err := url.Parse("tls://" + addr.String() + pin) From a42b77db84bf1488547a66147c8b5376520da784 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 27 Jun 2021 03:33:29 -0500 Subject: [PATCH 037/386] attempt to convert old multicast listen regexps into new struct format --- cmd/yggdrasil/main.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 79c243ba..67a822e4 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -96,6 +96,24 @@ func readConfig(log *log.Logger, useconf *bool, useconffile *string, normaliseco } } } + if oldmc, ok := dat["MulticastInterfaces"]; ok { + fmt.Println("DEBUG:", oldmc) + if oldmcvals, ok := oldmc.([]interface{}); ok { + var newmc []config.MulticastInterfaceConfig + for _, oldmcval := range oldmcvals { + if str, ok := oldmcval.(string); ok { + newmc = append(newmc, config.MulticastInterfaceConfig{ + Regex: str, + Incoming: true, + Outgoing: true, + }) + } + } + if newmc != nil { + dat["MulticastInterfaces"] = newmc + } + } + } // Sanitise the config confJson, err := json.Marshal(dat) if err != nil { From 4701f941a9f62f1e7234999052090358a1ccefd8 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 27 Jun 2021 09:42:46 +0100 Subject: [PATCH 038/386] Remove debug line --- cmd/yggdrasil/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 67a822e4..9572a177 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -97,7 +97,6 @@ func readConfig(log *log.Logger, useconf *bool, useconffile *string, normaliseco } } if oldmc, ok := dat["MulticastInterfaces"]; ok { - fmt.Println("DEBUG:", oldmc) if oldmcvals, ok := oldmc.([]interface{}); ok { var newmc []config.MulticastInterfaceConfig for _, oldmcval := range oldmcvals { From de853fed10adf946f1efbd4fad6aad87fc2c6d19 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 27 Jun 2021 17:24:46 -0500 Subject: [PATCH 039/386] multicast configuration changes --- cmd/yggdrasil/main.go | 14 +++++++-- src/config/config.go | 10 +++---- src/defaults/defaults_darwin.go | 4 +-- src/defaults/defaults_freebsd.go | 2 +- src/defaults/defaults_linux.go | 2 +- src/defaults/defaults_openbsd.go | 2 +- src/defaults/defaults_other.go | 2 +- src/defaults/defaults_windows.go | 2 +- src/multicast/multicast.go | 51 ++++++++++++++++---------------- 9 files changed, 49 insertions(+), 40 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 9572a177..55e6b261 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -102,13 +102,21 @@ func readConfig(log *log.Logger, useconf *bool, useconffile *string, normaliseco for _, oldmcval := range oldmcvals { if str, ok := oldmcval.(string); ok { newmc = append(newmc, config.MulticastInterfaceConfig{ - Regex: str, - Incoming: true, - Outgoing: true, + Regex: str, + Beacon: true, + Listen: true, }) } } if newmc != nil { + if oldport, ok := dat["LinkLocalTCPPort"]; ok { + // numbers parse to float64 by default + if port, ok := oldport.(float64); ok { + for idx := range newmc { + newmc[idx].Port = uint16(port) + } + } + } dat["MulticastInterfaces"] = newmc } } diff --git a/src/config/config.go b/src/config/config.go index d81907f5..041147b8 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -31,11 +31,10 @@ type NodeConfig struct { InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tls://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."` Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntls://0.0.0.0:0 or tls://[::]:0 to listen on all interfaces."` AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."` - MulticastInterfaces []MulticastInterfaceConfig `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."` + MulticastInterfaces []MulticastInterfaceConfig `comment:"Configuration for which interfaces multicast peer discovery should be\nenabled on. Each entry in the list should be a json object which may\ncontain Regex, Beacon, Listen, and Port. Regex is a regular expression\nwhich is matched against an interface name, and interfaces use the\nfirst configuration that they match gainst. Beacon configures whether\nor not the node should send link-local multicast beacons to advertise\ntheir presence, while listening for incoming connections on Port.\nListen controls whether or not the node listens for multicast beacons\nand opens outgoing connections."` AllowedPublicKeys []string `comment:"List of peer public keys to allow incoming peering connections\nfrom. If left empty/undefined then all connections will be allowed\nby default. This does not affect outgoing peerings, nor does it\naffect link-local peers discovered via multicast."` PublicKey string `comment:"Your public key. Your peers may ask you for this to put\ninto their AllowedPublicKeys configuration."` PrivateKey string `comment:"Your private key. DO NOT share this with anyone!"` - LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."` IfName string `comment:"Local network interface name for TUN adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN."` IfMTU uint64 `comment:"Maximum Transmission Unit (MTU) size for your local TUN interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` 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."` @@ -43,9 +42,10 @@ type NodeConfig struct { } type MulticastInterfaceConfig struct { - Regex string - Incoming bool - Outgoing bool + Regex string + Beacon bool + Listen bool + Port uint16 } // NewSigningKeys replaces the signing keypair in the NodeConfig with a new diff --git a/src/defaults/defaults_darwin.go b/src/defaults/defaults_darwin.go index a21539f7..e16f398f 100644 --- a/src/defaults/defaults_darwin.go +++ b/src/defaults/defaults_darwin.go @@ -14,8 +14,8 @@ func GetDefaults() platformDefaultParameters { // Multicast interfaces DefaultMulticastInterfaces: []MulticastInterfaceConfig{ - {Regex: "en.*", Incoming: true, Outgoing: true}, - {Regex: "bridge.*", Incoming: true, Outgoing: true}, + {Regex: "en.*", Beacon: true, Listen: true}, + {Regex: "bridge.*", Beacon: true, Listen: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_freebsd.go b/src/defaults/defaults_freebsd.go index 400ae29a..6c3e1c60 100644 --- a/src/defaults/defaults_freebsd.go +++ b/src/defaults/defaults_freebsd.go @@ -14,7 +14,7 @@ func GetDefaults() platformDefaultParameters { // Multicast interfaces DefaultMulticastInterfaces: []MulticastInterfaceConfig{ - {Regex: ".*", Incoming: true, Outgoing: true}, + {Regex: ".*", Beacon: true, Listen: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_linux.go b/src/defaults/defaults_linux.go index ac678d85..95c7ae95 100644 --- a/src/defaults/defaults_linux.go +++ b/src/defaults/defaults_linux.go @@ -14,7 +14,7 @@ func GetDefaults() platformDefaultParameters { // Multicast interfaces DefaultMulticastInterfaces: []MulticastInterfaceConfig{ - {Regex: ".*", Incoming: true, Outgoing: true}, + {Regex: ".*", Beacon: true, Listen: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_openbsd.go b/src/defaults/defaults_openbsd.go index f3e2376c..ef339546 100644 --- a/src/defaults/defaults_openbsd.go +++ b/src/defaults/defaults_openbsd.go @@ -14,7 +14,7 @@ func GetDefaults() platformDefaultParameters { // Multicast interfaces DefaultMulticastInterfaces: []MulticastInterfaceConfig{ - {Regex: ".*", Incoming: true, Outgoing: true}, + {Regex: ".*", Beacon: true, Listen: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_other.go b/src/defaults/defaults_other.go index d23c2ef0..d1417322 100644 --- a/src/defaults/defaults_other.go +++ b/src/defaults/defaults_other.go @@ -14,7 +14,7 @@ func GetDefaults() platformDefaultParameters { // Multicast interfaces DefaultMulticastInterfaces: []MulticastInterfaceConfig{ - {Regex: ".*", Incoming: true, Outgoing: true}, + {Regex: ".*", Beacon: true, Listen: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_windows.go b/src/defaults/defaults_windows.go index 1e918c3b..e81d09cf 100644 --- a/src/defaults/defaults_windows.go +++ b/src/defaults/defaults_windows.go @@ -14,7 +14,7 @@ func GetDefaults() platformDefaultParameters { // Multicast interfaces DefaultMulticastInterfaces: []MulticastInterfaceConfig{ - {Regex: ".*", Incoming: true, Outgoing: true}, + {Regex: ".*", Beacon: true, Listen: true}, }, // TUN/TAP diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index aea4e079..882911df 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -32,22 +32,23 @@ type Multicast struct { sock *ipv6.PacketConn groupAddr string listeners map[string]*listenerInfo - listenPort uint16 isOpen bool _interfaces map[string]interfaceInfo } type interfaceInfo struct { - iface net.Interface - addrs []net.Addr - incoming bool - outgoing bool + iface net.Interface + addrs []net.Addr + beacon bool + listen bool + port uint16 } type listenerInfo struct { listener *core.TcpListener time time.Time interval time.Duration + port uint16 } // Init prepares the multicast interface for use. @@ -57,7 +58,6 @@ func (m *Multicast) Init(core *core.Core, nc *config.NodeConfig, log *log.Logger m.log = log m.listeners = make(map[string]*listenerInfo) m._interfaces = make(map[string]interfaceInfo) - m.listenPort = m.config.LinkLocalTCPPort m.groupAddr = "[ff02::114]:9001" return nil } @@ -196,11 +196,12 @@ func (m *Multicast) getAllowedInterfaces() map[string]interfaceInfo { } // Does the interface match the regular expression? Store it if so if e.MatchString(iface.Name) { - if ifcfg.Incoming || ifcfg.Outgoing { + if ifcfg.Beacon || ifcfg.Listen { info := interfaceInfo{ - iface: iface, - incoming: ifcfg.Incoming, - outgoing: ifcfg.Outgoing, + iface: iface, + beacon: ifcfg.Beacon, + listen: ifcfg.Listen, + port: ifcfg.Port, } interfaces[iface.Name] = info } @@ -280,18 +281,18 @@ func (m *Multicast) _announce() { if !addrIP.IsLinkLocalUnicast() { continue } - if info.outgoing { - // Join the multicast group, so we can listen for advertisements to open outgoing connections + if info.listen { + // Join the multicast group, so we can listen for beacons _ = m.sock.JoinGroup(&iface, groupAddr) } - if !info.incoming { - break // Don't send multicast advertisements if we don't accept incoming connections + if !info.beacon { + break // Don't send multicast beacons or accept incoming connections } // Try and see if we already have a TCP listener for this interface - var info *listenerInfo + var linfo *listenerInfo if nfo, ok := m.listeners[iface.Name]; !ok || nfo.listener.Listener == nil { // No listener was found - let's create one - urlString := fmt.Sprintf("tls://[%s]:%d", addrIP, m.listenPort) + urlString := fmt.Sprintf("tls://[%s]:%d", addrIP, info.port) u, err := url.Parse(urlString) if err != nil { panic(err) @@ -299,24 +300,24 @@ func (m *Multicast) _announce() { if li, err := m.core.Listen(u, iface.Name); err == nil { m.log.Debugln("Started multicasting on", iface.Name) // Store the listener so that we can stop it later if needed - info = &listenerInfo{listener: li, time: time.Now()} - m.listeners[iface.Name] = info + linfo = &listenerInfo{listener: li, time: time.Now()} + m.listeners[iface.Name] = linfo } else { m.log.Warnln("Not multicasting on", iface.Name, "due to error:", err) } } else { // An existing listener was found - info = m.listeners[iface.Name] + linfo = m.listeners[iface.Name] } // Make sure nothing above failed for some reason - if info == nil { + if linfo == nil { continue } - if time.Since(info.time) < info.interval { + if time.Since(linfo.time) < linfo.interval { continue } // Get the listener details and construct the multicast beacon - lladdr := info.listener.Listener.Addr().String() + lladdr := linfo.listener.Listener.Addr().String() if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil { a.Zone = "" destAddr.Zone = iface.Name @@ -327,8 +328,8 @@ func (m *Multicast) _announce() { msg = append(msg, pbs...) _, _ = m.sock.WriteTo(msg, nil, destAddr) } - if info.interval.Seconds() < 15 { - info.interval += time.Second + if linfo.interval.Seconds() < 15 { + linfo.interval += time.Second } break } @@ -391,7 +392,7 @@ func (m *Multicast) listen() { phony.Block(m, func() { interfaces = m._interfaces }) - if info, ok := interfaces[from.Zone]; ok && info.outgoing { + if info, ok := interfaces[from.Zone]; ok && info.listen { addr.Zone = "" pin := fmt.Sprintf("/?key=%s", hex.EncodeToString(key)) u, err := url.Parse("tls://" + addr.String() + pin) From 3646a8674c418098f13e68fbc3fe9086bcdb2941 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 28 Jun 2021 18:21:53 +0100 Subject: [PATCH 040/386] Yggdrasil v0.4.0rc4 --- src/core/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/version.go b/src/core/version.go index 6676c7b6..0bfbbcbc 100644 --- a/src/core/version.go +++ b/src/core/version.go @@ -22,7 +22,7 @@ func version_getBaseMetadata() version_metadata { return version_metadata{ meta: [4]byte{'m', 'e', 't', 'a'}, ver: 0, - minorVer: 0, + minorVer: 4, } } From 9b28f725e23120e86f63ed07b285c8592d977323 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 28 Jun 2021 18:28:56 +0100 Subject: [PATCH 041/386] Fix core_test.go --- src/core/core_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/core_test.go b/src/core/core_test.go index 9a2f230f..dd60af21 100644 --- a/src/core/core_test.go +++ b/src/core/core_test.go @@ -11,11 +11,12 @@ import ( "github.com/gologme/log" "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/defaults" ) // GenerateConfig produces default configuration with suitable modifications for tests. func GenerateConfig() *config.NodeConfig { - cfg := config.GenerateConfig() + cfg := defaults.GenerateConfig() cfg.AdminListen = "none" cfg.Listen = []string{"tcp://127.0.0.1:0"} cfg.IfName = "none" From ff44417decc3e7f9ad702b2c67b1cfa6d4739785 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 1 Jul 2021 08:04:01 -0500 Subject: [PATCH 042/386] listen for SIGHUP, restart node (reload config file, listen for stdin again, etc) if we receive one --- cmd/yggdrasil/main.go | 112 +++++++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 23 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 55e6b261..84b0b11e 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "context" "crypto/ed25519" "encoding/hex" "encoding/json" @@ -41,15 +42,15 @@ type node struct { admin *admin.AdminSocket } -func readConfig(log *log.Logger, useconf *bool, useconffile *string, normaliseconf *bool) *config.NodeConfig { +func readConfig(log *log.Logger, useconf bool, useconffile string, normaliseconf bool) *config.NodeConfig { // Use a configuration file. If -useconf, the configuration will be read // from stdin. If -useconffile, the configuration will be read from the // filesystem. var conf []byte var err error - if *useconffile != "" { + if useconffile != "" { // Read the file from the filesystem - conf, err = ioutil.ReadFile(*useconffile) + conf, err = ioutil.ReadFile(useconffile) } else { // Read the file from stdin. conf, err = ioutil.ReadAll(os.Stdin) @@ -180,9 +181,21 @@ func setLogLevel(loglevel string, logger *log.Logger) { } } -// The main function is responsible for configuring and starting Yggdrasil. -func main() { - // Configure the command line parameters. +type yggArgs struct { + genconf bool + useconf bool + useconffile string + normaliseconf bool + confjson bool + autoconf bool + ver bool + logto string + getaddr bool + getsnet bool + loglevel string +} + +func getArgs() yggArgs { genconf := flag.Bool("genconf", false, "print a new config to stdout") useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin") useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path") @@ -195,10 +208,43 @@ func main() { getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration") loglevel := flag.String("loglevel", "info", "loglevel to enable") flag.Parse() + return yggArgs{ + genconf: *genconf, + useconf: *useconf, + useconffile: *useconffile, + normaliseconf: *normaliseconf, + confjson: *confjson, + autoconf: *autoconf, + ver: *ver, + logto: *logto, + getaddr: *getaddr, + getsnet: *getsnet, + loglevel: *loglevel, + } +} + +// The main function is responsible for configuring and starting Yggdrasil. +func run(args yggArgs, ctx context.Context, done chan struct{}) { + defer close(done) + // Configure the command line parameters. + /* + genconf := flag.Bool("genconf", false, "print a new config to stdout") + useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin") + useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path") + normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised") + confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON") + autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") + ver := flag.Bool("version", false, "prints the version of this build") + logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"") + getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration") + getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration") + loglevel := flag.String("loglevel", "info", "loglevel to enable") + flag.Parse() + */ // Create a new logger that logs output to stdout. var logger *log.Logger - switch *logto { + switch args.logto { case "stdout": logger = log.New(os.Stdout, "", log.Flags()) case "syslog": @@ -206,7 +252,7 @@ func main() { logger = log.New(syslogger, "", log.Flags()) } default: - if logfd, err := os.OpenFile(*logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil { + if logfd, err := os.OpenFile(args.logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil { logger = log.New(logfd, "", log.Flags()) } } @@ -215,33 +261,33 @@ func main() { logger.Warnln("Logging defaulting to stdout") } - if *normaliseconf { + if args.normaliseconf { setLogLevel("error", logger) } else { - setLogLevel(*loglevel, logger) + setLogLevel(args.loglevel, logger) } var cfg *config.NodeConfig var err error switch { - case *ver: + case args.ver: fmt.Println("Build name:", version.BuildName()) fmt.Println("Build version:", version.BuildVersion()) return - case *autoconf: + case args.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 = defaults.GenerateConfig() - case *useconffile != "" || *useconf: + case args.useconffile != "" || args.useconf: // Read the configuration from either stdin or from the filesystem - cfg = readConfig(logger, useconf, useconffile, normaliseconf) + cfg = readConfig(logger, args.useconf, args.useconffile, args.normaliseconf) // If the -normaliseconf option was specified then remarshal the above // configuration and print it back to stdout. This lets the user update // their configuration file with newly mapped names (like above) or to // convert from plain JSON to commented HJSON. - if *normaliseconf { + if args.normaliseconf { var bs []byte - if *confjson { + if args.confjson { bs, err = json.MarshalIndent(cfg, "", " ") } else { bs, err = hjson.Marshal(cfg) @@ -252,9 +298,9 @@ func main() { fmt.Println(string(bs)) return } - case *genconf: + case args.genconf: // Generate a new configuration and print it to stdout. - fmt.Println(doGenconf(*confjson)) + fmt.Println(doGenconf(args.confjson)) default: // No flags were provided, therefore print the list of flags to stdout. flag.PrintDefaults() @@ -273,14 +319,14 @@ func main() { return nil } switch { - case *getaddr: + case args.getaddr: if key := getNodeKey(); key != nil { addr := address.AddrForKey(key) ip := net.IP(addr[:]) fmt.Println(ip.String()) } return - case *getsnet: + case args.getsnet: if key := getNodeKey(); key != nil { snet := address.SubnetForKey(key) ipnet := net.IPNet{ @@ -337,10 +383,8 @@ func main() { logger.Infof("Your IPv6 address is %s", address.String()) logger.Infof("Your IPv6 subnet is %s", subnet.String()) // Catch interrupts from the operating system to exit gracefully. - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt, syscall.SIGTERM) + <-ctx.Done() // Capture the service being stopped on Windows. - <-c minwinsvc.SetOnExit(n.shutdown) n.shutdown() } @@ -351,3 +395,25 @@ func (n *node) shutdown() { _ = n.tuntap.Stop() n.core.Stop() } + +func main() { + args := getArgs() + hup := make(chan os.Signal, 1) + signal.Notify(hup, os.Interrupt, syscall.SIGHUP) + term := make(chan os.Signal, 1) + signal.Notify(term, os.Interrupt, syscall.SIGTERM) + for { + done := make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) + go run(args, ctx, done) + select { + case <-hup: + cancel() + <-done + case <-term: + cancel() + <-done + return + } + } +} From df44b0227b743ef2fbfed01a2b32340843565f52 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 1 Jul 2021 08:54:14 -0500 Subject: [PATCH 043/386] disable SIGHUP handling for now --- cmd/yggdrasil/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 84b0b11e..c8165175 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -399,7 +399,7 @@ func (n *node) shutdown() { func main() { args := getArgs() hup := make(chan os.Signal, 1) - signal.Notify(hup, os.Interrupt, syscall.SIGHUP) + //signal.Notify(hup, os.Interrupt, syscall.SIGHUP) term := make(chan os.Signal, 1) signal.Notify(term, os.Interrupt, syscall.SIGTERM) for { From b07caa1e0ac7208be2a4b93c5a219e90caac77e5 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 1 Jul 2021 19:32:55 -0500 Subject: [PATCH 044/386] add first draft of changelog --- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 856f1cea..50f91dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,32 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.4.0] - 2021-07-04 +### Added +- Connections to TLS peers will now pin the public ed25519 key used in the TLS handshake, or check that the handshake key matches the existing pinned key for that peer (if a key was pinned) + +### Changed +- This version is backwards incompatible with previous versions of Yggdrasil. The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4. Nodes running this version will **not** be able to peer with earlier versions of Yggdrasil. Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release. Please also note that nodes may be removed from the public peers repository if they do not upgrade within some reasonable amount of time (think days or weeks, not months), and a large fraction of nodes on the public peers list may be unusable (offline or running an old and incompatible version) until that cleanup happens +- IP addresses are derived from ed25519 public (signing) keys. Previously, addresses were derived from a hash of X25519 (Diffie-Hellman) keys. Note that this means **all node addresses have changed with respect to previous releases**, so any existing services will be hosted at new addresses. The services page of the main repo has been updated to only list services in the new v0.4 network. Service operators are encouraged to submit a PR if they wish to be (re-)added to the list +- Link-local peers from multicast peer discovery will now connect over TLS. This is part of a general effort to encourage peering over TLS by default. Note that traffic is encrypted end-to-end regardless of how peer connections are established +- Multicast peer discovery is now more configurable. There are separate configuration options to control if beacons are sent, what port to listen on for incoming connections (if sending beacons), and whether or not to listen for beacons from other nodes (and open connections when receiving a beacon). Each configuration entry in the list specifies a regular expression to match against interface names. If an interface matches multiple regex in the list, it will use the settings for the first entry in the list that it matches with +- `socks://` peers now expect the destination endpoint to be a `tls://` listener +- The configuration file format has been updated. Among other things, there is now a single `PublicKey` and `PrivateKey` pair, both corresponding to ed25519 keys (since nodes no longer have a permanent X25519 key pair) +- Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code. The list of available functions will likely be expanded in future releases +- The session and routing code has been redesigned and rewritten as a [standalone library](https://github.com/Arceliar/ironwood). We expect to see reduced bandwidth use and improved reliability with the new design, especially in mobile networks. This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base. Please bear with us for these next few releases as we work through any bugs or issues +- Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (both nodes will rotate keys at least once per round trip exchange of traffic, which is arguably *too* aggressive, we may throttle this somehow in a future release) +- Source routing has been added. Under normal circumstances, this is what is used to forward session traffic (e.g. the user's IPv6 traffic) +- DHT-based routing has been added. This is used when the sender does not know a source route to the destination. Forwarding through the DHT is less efficient, but the only information that it requires the sender to know is the destination node's (static) key. This is primarily used during the key exchange at session setup, or as a temporary fallback when a source route fails due to changes in the network +- The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) + +### Removed +- TunnelRouting (aka cryptokey routing) has been removed. We recommend tunneling an existing standard over Yggdrasil instead (e.g. `ip6gre` and `ip6gretap`) +- SessionFirewall has been removed. This was never a true firewall, it was simply a way to prevent a node from being flooded with unwanted sessions. The new code base needs to address that problem in other ways. Users who want a firewall or other packet filter should configure something supported by their OS (e.g. `ip6tables`) +- SIGHUP handling has been removed. SIGHUP will be handled normally (by exiting) instead of attempting to reload (parts of) the config file +- The whitepaper (and the rest of the doc folder) has been removed. This documentation was outdated since the routing code as been rewritten. New documentation will likely appear in a future release +- `cmd/yggrasilsim` has been removed. Since the routing code is now a separate library, it probably makes more sense to rewrite this as part of the library test code (or otherwise keep it separate from this repo) +- DHT lookups have been removed. This means there's nothing in the protocol that inherently makes it possible to crawl through the network. That said, `yggdrasilctl` exposes several remote `debug` functions, which make it possible to continue crawling the network. These will also be removed in a future release, if/when we're reasonably confident that things are working as intended + ## [0.3.16] - 2021-03-18 ### Added - New simulation code under `cmd/yggdrasilsim` (work-in-progress) From 9239ed70e472a8d7fc3bda279fd65e7be98dcf3b Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 1 Jul 2021 20:06:05 -0500 Subject: [PATCH 045/386] changelog revisions --- CHANGELOG.md | 68 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50f91dd9..c4c82d3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,29 +27,59 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.4.0] - 2021-07-04 ### Added -- Connections to TLS peers will now pin the public ed25519 key used in the TLS handshake, or check that the handshake key matches the existing pinned key for that peer (if a key was pinned) +- TLS connections now use public key pinning + - If no public key was already pinned, then the public key received as part of the TLS handshake is pinned to the connection + - The public key received as part of the handshake is checked against the pinned keys, and if no match is found, the connection is rejected ### Changed -- This version is backwards incompatible with previous versions of Yggdrasil. The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4. Nodes running this version will **not** be able to peer with earlier versions of Yggdrasil. Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release. Please also note that nodes may be removed from the public peers repository if they do not upgrade within some reasonable amount of time (think days or weeks, not months), and a large fraction of nodes on the public peers list may be unusable (offline or running an old and incompatible version) until that cleanup happens -- IP addresses are derived from ed25519 public (signing) keys. Previously, addresses were derived from a hash of X25519 (Diffie-Hellman) keys. Note that this means **all node addresses have changed with respect to previous releases**, so any existing services will be hosted at new addresses. The services page of the main repo has been updated to only list services in the new v0.4 network. Service operators are encouraged to submit a PR if they wish to be (re-)added to the list -- Link-local peers from multicast peer discovery will now connect over TLS. This is part of a general effort to encourage peering over TLS by default. Note that traffic is encrypted end-to-end regardless of how peer connections are established -- Multicast peer discovery is now more configurable. There are separate configuration options to control if beacons are sent, what port to listen on for incoming connections (if sending beacons), and whether or not to listen for beacons from other nodes (and open connections when receiving a beacon). Each configuration entry in the list specifies a regular expression to match against interface names. If an interface matches multiple regex in the list, it will use the settings for the first entry in the list that it matches with -- `socks://` peers now expect the destination endpoint to be a `tls://` listener -- The configuration file format has been updated. Among other things, there is now a single `PublicKey` and `PrivateKey` pair, both corresponding to ed25519 keys (since nodes no longer have a permanent X25519 key pair) -- Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code. The list of available functions will likely be expanded in future releases -- The session and routing code has been redesigned and rewritten as a [standalone library](https://github.com/Arceliar/ironwood). We expect to see reduced bandwidth use and improved reliability with the new design, especially in mobile networks. This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base. Please bear with us for these next few releases as we work through any bugs or issues -- Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (both nodes will rotate keys at least once per round trip exchange of traffic, which is arguably *too* aggressive, we may throttle this somehow in a future release) -- Source routing has been added. Under normal circumstances, this is what is used to forward session traffic (e.g. the user's IPv6 traffic) -- DHT-based routing has been added. This is used when the sender does not know a source route to the destination. Forwarding through the DHT is less efficient, but the only information that it requires the sender to know is the destination node's (static) key. This is primarily used during the key exchange at session setup, or as a temporary fallback when a source route fails due to changes in the network -- The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) +- This version is backwards incompatible with previous versions of Yggdrasil + - The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4 + - Nodes running this version will **not** be able to peer with earlier versions of Yggdrasil + - Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release + - Please also note that nodes may be removed from the public peers repository if they do not upgrade within some time period after release (perhaps a couple of weeks) +- IP addresses are derived from ed25519 public (signing) keys + - Previously, addresses were derived from a hash of X25519 (Diffie-Hellman) keys + - Note that this means **all node addresses have changed with respect to previous releases**, so any existing services will be hosted at new addresses + - The services page of the main repo has been updated to only list services in the new v0.4 network + - Service operators are encouraged to submit a PR if they wish to be (re-)added to the list +- It is now recommended to peer over TLS + - Link-local peers from multicast peer discovery will now connect over TLS, with the key from the multicast announcement pinned to the connection + - `socks://` peers now expect the destination endpoint to be a `tls://` listener +- Multicast peer discovery is now more configurable + - There are separate configuration options to control if beacons are sent, what port to listen on for incoming connections (if sending beacons), and whether or not to listen for beacons from other nodes (and open connections when receiving a beacon) + - Each configuration entry in the list specifies a regular expression to match against interface names + - If an interface matches multiple regex in the list, it will use the settings for the first entry in the list that it matches with +- The session and routing code has been redesigned and rewritten: + - This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base. Please bear with us for these next few releases as we work through any bugs or issues + - Generally speaking, we expect to see reduced bandwidth use and improved reliability with the new design, especially in mobile networks + - Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (both nodes will rotate keys at least once per round trip exchange of traffic, which is arguably *too* aggressive, we may throttle this somehow in a future release) + - Source routing has been added. Under normal circumstances, this is what is used to forward session traffic (e.g. the user's IPv6 traffic) + - DHT-based routing has been added. This is used when the sender does not know a source route to the destination. Forwarding through the DHT is less efficient, but the only information that it requires the sender to know is the destination node's (static) key. This is primarily used during the key exchange at session setup, or as a temporary fallback when a source route fails due to changes in the network + - The new DHT design does not support crawling, and does not inherently allow nodes to look up the owner of an arbitrary key. In Yggdrasil, responding to lookups is implemented at the application level, and a response is only sent if the destination key matches the node's IP or /64 prefix + - The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) + - The code now lives in a [standalone library](https://github.com/Arceliar/ironwood). You are encouraged **not** to use it, as it's still considered pre-alpha, but it's available for those who want to experiment with the new routing algorithm in other contexts +- Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code + - Several remote `debug` functions have been added temporarily, to allow for crawling and census gathering during the transition to the new version, but we intend to remove this at some point in the (possibly distant) future + - The list of available functions will likely be expanded in future releases +- The configuration file format has been updated in response to the changed/removed features ### Removed -- TunnelRouting (aka cryptokey routing) has been removed. We recommend tunneling an existing standard over Yggdrasil instead (e.g. `ip6gre` and `ip6gretap`) -- SessionFirewall has been removed. This was never a true firewall, it was simply a way to prevent a node from being flooded with unwanted sessions. The new code base needs to address that problem in other ways. Users who want a firewall or other packet filter should configure something supported by their OS (e.g. `ip6tables`) -- SIGHUP handling has been removed. SIGHUP will be handled normally (by exiting) instead of attempting to reload (parts of) the config file -- The whitepaper (and the rest of the doc folder) has been removed. This documentation was outdated since the routing code as been rewritten. New documentation will likely appear in a future release -- `cmd/yggrasilsim` has been removed. Since the routing code is now a separate library, it probably makes more sense to rewrite this as part of the library test code (or otherwise keep it separate from this repo) -- DHT lookups have been removed. This means there's nothing in the protocol that inherently makes it possible to crawl through the network. That said, `yggdrasilctl` exposes several remote `debug` functions, which make it possible to continue crawling the network. These will also be removed in a future release, if/when we're reasonably confident that things are working as intended +- TunnelRouting (aka cryptokey routing) has been removed + - It was too easy to accidentally break routing by capturing the route to peers with the tun adapter + - We recommend tunneling an existing standard over Yggdrasil instead (e.g. `ip6gre` and `ip6gretap`) +- SessionFirewall has been removed + - This was never a true firewall, it was simply a way to prevent a node from being flooded with unwanted sessions, so the name could be misleading and lead to a false sense of security + - Due to design changes, the new code needs to address the possible memory exhaustion attacks in other ways, and a single configurable list no longer makes sense + - Users who want a firewall or other packet filter mechansim should configure something supported by their OS instead (e.g. `ip6tables`) +- SIGHUP handling has been removed + - Previously, we set a custom SIGHUP handler, and used it to reload (parts of) the config file + - It was never obvious which parts could be reloaded while live, and which required the application to be killed and restarted to take effect + - Reloading the config without restarting was also a delicate and bug-prone process, and was distracting from more important developments + - SIGHUP will be handled normally (i.e. by exiting) +- The `doc` folder has been removed + - In light of the routing scheme's redesign and reimplementation, the documentation was out out-of-date + - New documentation may be added in a future release +- `cmd/yggrasilsim` has been removed, and is unlikely to return to this repository ## [0.3.16] - 2021-03-18 ### Added From 9391430bc08e91a99ca7dbc713c3cdcc4a12d66d Mon Sep 17 00:00:00 2001 From: Chris Hills Date: Fri, 2 Jul 2021 12:53:05 +0100 Subject: [PATCH 046/386] Update binary path in systemd service files to match the website. --- contrib/systemd/yggdrasil-default-config.service | 4 ++-- contrib/systemd/yggdrasil.service | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/systemd/yggdrasil-default-config.service b/contrib/systemd/yggdrasil-default-config.service index e9fe45be..b5af52f8 100644 --- a/contrib/systemd/yggdrasil-default-config.service +++ b/contrib/systemd/yggdrasil-default-config.service @@ -9,5 +9,5 @@ After=local-fs.target Type=oneshot Group=yggdrasil StandardOutput=file:/etc/yggdrasil.conf -ExecStart=/usr/bin/yggdrasil -genconf -ExecStartPost=/usr/bin/chmod 0640 /etc/yggdrasil.conf +ExecStart=/usr/local/bin/yggdrasil -genconf +ExecStartPost=/usr/local/bin/chmod 0640 /etc/yggdrasil.conf diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 3002e61b..44afaf2b 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -12,7 +12,7 @@ ProtectSystem=true SyslogIdentifier=yggdrasil CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW ExecStartPre=+-/sbin/modprobe tun -ExecStart=/usr/bin/yggdrasil -useconffile /etc/yggdrasil.conf +ExecStart=/usr/local/bin/yggdrasil -useconffile /etc/yggdrasil.conf ExecReload=/bin/kill -HUP $MAINPID Restart=always TimeoutStopSec=5 From ccf03847fc701452ad95e11ea502e358c4b1901f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 2 Jul 2021 23:07:44 +0100 Subject: [PATCH 047/386] Update changelog --- CHANGELOG.md | 55 ++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4c82d3e..4487ba25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,58 +27,53 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.4.0] - 2021-07-04 ### Added +- New routing scheme, which is backwards incompatible with previous versions of Yggdrasil + - The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4 + - Nodes running this new version **will not** be able to peer with earlier versions of Yggdrasil + - Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release - TLS connections now use public key pinning - If no public key was already pinned, then the public key received as part of the TLS handshake is pinned to the connection - The public key received as part of the handshake is checked against the pinned keys, and if no match is found, the connection is rejected ### Changed -- This version is backwards incompatible with previous versions of Yggdrasil - - The wire protocol version number, exchanged as part of the peer setup handshake, has been increased to 0.4 - - Nodes running this version will **not** be able to peer with earlier versions of Yggdrasil - - Please note that **the network may be temporarily unstable** while infrastructure is being upgraded to the new release - - Please also note that nodes may be removed from the public peers repository if they do not upgrade within some time period after release (perhaps a couple of weeks) -- IP addresses are derived from ed25519 public (signing) keys +- IP addresses are now derived from ed25519 public (signing) keys - Previously, addresses were derived from a hash of X25519 (Diffie-Hellman) keys - - Note that this means **all node addresses have changed with respect to previous releases**, so any existing services will be hosted at new addresses - - The services page of the main repo has been updated to only list services in the new v0.4 network - - Service operators are encouraged to submit a PR if they wish to be (re-)added to the list + - Importantly, this means that **all internal IPv6 addresses will change with this release** — this will affect anyone running public services or relying on Yggdrasil for remote access - It is now recommended to peer over TLS - - Link-local peers from multicast peer discovery will now connect over TLS, with the key from the multicast announcement pinned to the connection - - `socks://` peers now expect the destination endpoint to be a `tls://` listener + - Link-local peers from multicast peer discovery will now connect over TLS, with the key from the multicast beacon pinned to the connection + - `socks://` peers now expect the destination endpoint to be a `tls://` listener, instead of a `tcp://` listener - Multicast peer discovery is now more configurable - There are separate configuration options to control if beacons are sent, what port to listen on for incoming connections (if sending beacons), and whether or not to listen for beacons from other nodes (and open connections when receiving a beacon) - Each configuration entry in the list specifies a regular expression to match against interface names - If an interface matches multiple regex in the list, it will use the settings for the first entry in the list that it matches with -- The session and routing code has been redesigned and rewritten: - - This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base. Please bear with us for these next few releases as we work through any bugs or issues - - Generally speaking, we expect to see reduced bandwidth use and improved reliability with the new design, especially in mobile networks - - Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (both nodes will rotate keys at least once per round trip exchange of traffic, which is arguably *too* aggressive, we may throttle this somehow in a future release) +- The session and routing code has been entirely redesigned and rewritten + - This is still an early work-in-progress, so the code hasn't been as well tested or optimized as the old code base — please bear with us for these next few releases as we work through any bugs or issues + - Generally speaking, we expect to see reduced bandwidth use and improved reliability with the new design, especially in cases where nodes move around or change peerings frequently + - Cryptographic sessions no longer use a single shared (ephemeral) secret for the entire life of the session. Keys are now rotated regularly for ongoing sessions (currently rotated at least once per round trip exchange of traffic, subject to change in future releases) - Source routing has been added. Under normal circumstances, this is what is used to forward session traffic (e.g. the user's IPv6 traffic) - DHT-based routing has been added. This is used when the sender does not know a source route to the destination. Forwarding through the DHT is less efficient, but the only information that it requires the sender to know is the destination node's (static) key. This is primarily used during the key exchange at session setup, or as a temporary fallback when a source route fails due to changes in the network - - The new DHT design does not support crawling, and does not inherently allow nodes to look up the owner of an arbitrary key. In Yggdrasil, responding to lookups is implemented at the application level, and a response is only sent if the destination key matches the node's IP or /64 prefix + - The new DHT design is no longer RPC-based, does not support crawling and does not inherently allow nodes to look up the owner of an arbitrary key. Responding to lookups is now implemented at the application level and a response is only sent if the destination key matches the node's `/128` IP or `/64` prefix - The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) - - The code now lives in a [standalone library](https://github.com/Arceliar/ironwood). You are encouraged **not** to use it, as it's still considered pre-alpha, but it's available for those who want to experiment with the new routing algorithm in other contexts + - The routing logic now lives in a [standalone library](https://github.com/Arceliar/ironwood). You are encouraged **not** to use it, as it's still considered pre-alpha, but it's available for those who want to experiment with the new routing algorithm in other contexts - Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code - Several remote `debug` functions have been added temporarily, to allow for crawling and census gathering during the transition to the new version, but we intend to remove this at some point in the (possibly distant) future - The list of available functions will likely be expanded in future releases - The configuration file format has been updated in response to the changed/removed features ### Removed -- TunnelRouting (aka cryptokey routing) has been removed - - It was too easy to accidentally break routing by capturing the route to peers with the tun adapter - - We recommend tunneling an existing standard over Yggdrasil instead (e.g. `ip6gre` and `ip6gretap`) -- SessionFirewall has been removed - - This was never a true firewall, it was simply a way to prevent a node from being flooded with unwanted sessions, so the name could be misleading and lead to a false sense of security - - Due to design changes, the new code needs to address the possible memory exhaustion attacks in other ways, and a single configurable list no longer makes sense +- Tunnel routing (a.k.a. crypto-key routing or "CKR") has been removed + - It was far too easy to accidentally break routing altogether by capturing the route to peers with the TUN adapter + - We recommend tunnelling an existing standard over Yggdrasil instead (e.g. `ip6gre`, `ip6gretap` or other encapsulations) + - All `TunnelRouting` configuration options will no longer take effect +- Session firewall has been removed + - This was never a true firewall — it didn't behave like a stateful IP firewall, often allowed return traffic unexpectedly and was simply a way to prevent a node from being flooded with unwanted sessions, so the name could be misleading and usually lead to a false sense of security + - Due to design changes, the new code needs to address the possible memory exhaustion attacks in other ways and a single configurable list no longer makes sense - Users who want a firewall or other packet filter mechansim should configure something supported by their OS instead (e.g. `ip6tables`) -- SIGHUP handling has been removed - - Previously, we set a custom SIGHUP handler, and used it to reload (parts of) the config file - - It was never obvious which parts could be reloaded while live, and which required the application to be killed and restarted to take effect + - All `SessionFirewall` configuration options will no longer take effect +- `SIGHUP` handling to reload the configuration at runtime has been removed + - It was not obvious which parts of the configuration could be reloaded at runtime, and which required the application to be killed and restarted to take effect - Reloading the config without restarting was also a delicate and bug-prone process, and was distracting from more important developments - - SIGHUP will be handled normally (i.e. by exiting) -- The `doc` folder has been removed - - In light of the routing scheme's redesign and reimplementation, the documentation was out out-of-date - - New documentation may be added in a future release + - `SIGHUP` will be handled normally (i.e. by exiting) - `cmd/yggrasilsim` has been removed, and is unlikely to return to this repository ## [0.3.16] - 2021-03-18 From 540e0bc2ce92202745ed49891d8bb3adbe36b749 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 2 Jul 2021 23:11:16 +0100 Subject: [PATCH 048/386] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4487ba25..bdb634f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - The new DHT design is no longer RPC-based, does not support crawling and does not inherently allow nodes to look up the owner of an arbitrary key. Responding to lookups is now implemented at the application level and a response is only sent if the destination key matches the node's `/128` IP or `/64` prefix - The greedy routing scheme, used to forward all traffic in previous releases, is now only used for protocol traffic (i.e. DHT setup and source route discovery) - The routing logic now lives in a [standalone library](https://github.com/Arceliar/ironwood). You are encouraged **not** to use it, as it's still considered pre-alpha, but it's available for those who want to experiment with the new routing algorithm in other contexts + - Session MTUs may be slightly lower now, in order to accommodate large packet headers if required - Many of the admin functions available over `yggdrasilctl` have been changed or removed as part of rewrites to the code - Several remote `debug` functions have been added temporarily, to allow for crawling and census gathering during the transition to the new version, but we intend to remove this at some point in the (possibly distant) future - The list of available functions will likely be expanded in future releases @@ -63,7 +64,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Removed - Tunnel routing (a.k.a. crypto-key routing or "CKR") has been removed - It was far too easy to accidentally break routing altogether by capturing the route to peers with the TUN adapter - - We recommend tunnelling an existing standard over Yggdrasil instead (e.g. `ip6gre`, `ip6gretap` or other encapsulations) + - We recommend tunnelling an existing standard over Yggdrasil instead (e.g. `ip6gre`, `ip6gretap` or other similar encapsulations, using Yggdrasil IPv6 addresses as the tunnel endpoints) - All `TunnelRouting` configuration options will no longer take effect - Session firewall has been removed - This was never a true firewall — it didn't behave like a stateful IP firewall, often allowed return traffic unexpectedly and was simply a way to prevent a node from being flooded with unwanted sessions, so the name could be misleading and usually lead to a false sense of security From 4d47ba8bf4815855d75cb2fcac3568aadb8cecad Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 2 Jul 2021 23:21:38 +0100 Subject: [PATCH 049/386] Update README.md --- README.md | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d1d254a6..a709ae4e 100644 --- a/README.md +++ b/README.md @@ -20,25 +20,11 @@ internet-like topologies. ## Supported Platforms -We actively support the following platforms, and packages are available for -some of the below: +Yggdrasil works on a number of platforms, including Linux, macOS, Ubiquiti +EdgeRouter, VyOS, Windows, FreeBSD, OpenBSD and OpenWrt. -- Linux - - `.deb` and `.rpm` packages are built by CI for Debian and Red Hat-based - distributions - - Arch, Nix, Void packages also available within their respective repositories -- macOS - - `.pkg` packages are built by CI -- Ubiquiti EdgeOS - - `.deb` Vyatta packages are built by CI -- Windows -- FreeBSD -- OpenBSD -- OpenWrt - -Please see our [Platforms](https://yggdrasil-network.github.io/platforms.html) pages for more -specific information about each of our supported platforms, including -installation steps and caveats. +Please see our [Installation](https://yggdrasil-network.github.io/installation.html) +page for more information. You may also find other platform-specific wrappers, scripts or tools in the `contrib` folder. @@ -97,21 +83,18 @@ by giving the Yggdrasil binary the `CAP_NET_ADMIN` capability. ## Documentation -Documentation is available on our [GitHub -Pages](https://yggdrasil-network.github.io) site, or in the base submodule -repository within `doc/yggdrasil-network.github.io`. +Documentation is available on our [GitHub Pages](https://yggdrasil-network.github.io) +site. -- [Configuration file options](https://yggdrasil-network.github.io/configuration.html) -- [Platform-specific documentation](https://yggdrasil-network.github.io/platforms.html) +- [Configuration file](https://yggdrasil-network.github.io/configuration.html) - [Frequently asked questions](https://yggdrasil-network.github.io/faq.html) -- [Admin API documentation](https://yggdrasil-network.github.io/admin.html) - [Version changelog](CHANGELOG.md) ## Community Feel free to join us on our [Matrix channel](https://matrix.to/#/#yggdrasil:matrix.org) at `#yggdrasil:matrix.org` -or in the `#yggdrasil` IRC channel on Freenode. +or in the `#yggdrasil` IRC channel on [libera.chat](https://libera.chat). ## License From f7b91a8f939420f74ce8b911a6690fc961086033 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 2 Jul 2021 23:24:34 +0100 Subject: [PATCH 050/386] Update README.md --- README.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a709ae4e..f1f71d11 100644 --- a/README.md +++ b/README.md @@ -11,23 +11,14 @@ allows pretty much any IPv6-capable application to communicate securely with other Yggdrasil nodes. Yggdrasil does not require you to have IPv6 Internet connectivity - it also works over IPv4. -Although Yggdrasil shares many similarities with -[cjdns](https://github.com/cjdelisle/cjdns), it employs a different routing -algorithm based on a globally-agreed spanning tree and greedy routing in a -metric space, and aims to implement some novel local backpressure routing -techniques. In theory, Yggdrasil should scale well on networks with -internet-like topologies. - ## Supported Platforms Yggdrasil works on a number of platforms, including Linux, macOS, Ubiquiti EdgeRouter, VyOS, Windows, FreeBSD, OpenBSD and OpenWrt. Please see our [Installation](https://yggdrasil-network.github.io/installation.html) -page for more information. - -You may also find other platform-specific wrappers, scripts or tools in the -`contrib` folder. +page for more information. You may also find other platform-specific wrappers, scripts +or tools in the `contrib` folder. ## Building @@ -83,10 +74,10 @@ by giving the Yggdrasil binary the `CAP_NET_ADMIN` capability. ## Documentation -Documentation is available on our [GitHub Pages](https://yggdrasil-network.github.io) -site. +Documentation is available [on our website](https://yggdrasil-network.github.io). -- [Configuration file](https://yggdrasil-network.github.io/configuration.html) +- [Installing Yggdrasil](https://yggdrasil-network.github.io/installation.html) +- [Configuring Yggdrasil](https://yggdrasil-network.github.io/configuration.html) - [Frequently asked questions](https://yggdrasil-network.github.io/faq.html) - [Version changelog](CHANGELOG.md) From 5844079f67de4909c8479221598de73c3a8b6132 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 3 Jul 2021 17:27:00 -0500 Subject: [PATCH 051/386] make sure genconf exits, clean up some commented out code --- cmd/yggdrasil/main.go | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index c8165175..d6d0d1a6 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -226,22 +226,6 @@ func getArgs() yggArgs { // The main function is responsible for configuring and starting Yggdrasil. func run(args yggArgs, ctx context.Context, done chan struct{}) { defer close(done) - // Configure the command line parameters. - /* - genconf := flag.Bool("genconf", false, "print a new config to stdout") - useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin") - useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path") - normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised") - confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON") - autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)") - ver := flag.Bool("version", false, "prints the version of this build") - logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"") - getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration") - getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration") - loglevel := flag.String("loglevel", "info", "loglevel to enable") - flag.Parse() - */ - // Create a new logger that logs output to stdout. var logger *log.Logger switch args.logto { @@ -301,6 +285,7 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) { case args.genconf: // Generate a new configuration and print it to stdout. fmt.Println(doGenconf(args.confjson)) + return default: // No flags were provided, therefore print the list of flags to stdout. flag.PrintDefaults() @@ -414,6 +399,8 @@ func main() { cancel() <-done return + case <-done: + return } } } From 2fc34bbd5a17e002b323017de5d14a69c5940421 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 4 Jul 2021 09:26:17 +0100 Subject: [PATCH 052/386] Revert "Merge pull request #796 from Chaz6/update-systemd-files" This reverts commit 88bd098f91fdf7ca693018ab7982f680b5c9db92, reversing changes made to 4d798a34940af2eacba73f274ea9260fb57e8452. --- contrib/systemd/yggdrasil-default-config.service | 4 ++-- contrib/systemd/yggdrasil.service | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/systemd/yggdrasil-default-config.service b/contrib/systemd/yggdrasil-default-config.service index b5af52f8..e9fe45be 100644 --- a/contrib/systemd/yggdrasil-default-config.service +++ b/contrib/systemd/yggdrasil-default-config.service @@ -9,5 +9,5 @@ After=local-fs.target Type=oneshot Group=yggdrasil StandardOutput=file:/etc/yggdrasil.conf -ExecStart=/usr/local/bin/yggdrasil -genconf -ExecStartPost=/usr/local/bin/chmod 0640 /etc/yggdrasil.conf +ExecStart=/usr/bin/yggdrasil -genconf +ExecStartPost=/usr/bin/chmod 0640 /etc/yggdrasil.conf diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 44afaf2b..3002e61b 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -12,7 +12,7 @@ ProtectSystem=true SyslogIdentifier=yggdrasil CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW ExecStartPre=+-/sbin/modprobe tun -ExecStart=/usr/local/bin/yggdrasil -useconffile /etc/yggdrasil.conf +ExecStart=/usr/bin/yggdrasil -useconffile /etc/yggdrasil.conf ExecReload=/bin/kill -HUP $MAINPID Restart=always TimeoutStopSec=5 From f990a56046646ef97322c910b8cd057e99ad035d Mon Sep 17 00:00:00 2001 From: Arceliar Date: Mon, 5 Jul 2021 13:14:12 -0500 Subject: [PATCH 053/386] have the core wrap and export the underlying PacketConn, move IPv6 ReadWriteCloser wrapper logic to a separate package --- cmd/yggdrasil/main.go | 4 +- src/core/api.go | 42 +------ src/core/core.go | 62 ++++++++- src/core/link.go | 2 +- src/core/nodeinfo.go | 4 +- src/core/proto.go | 9 +- src/core/types.go | 7 -- src/{core => ipv6rwc}/icmpv6.go | 2 +- src/{core/keystore.go => ipv6rwc/ipv6rwc.go} | 125 +++++++++++++------ src/tuntap/iface.go | 4 +- src/tuntap/tun.go | 19 ++- 11 files changed, 170 insertions(+), 110 deletions(-) rename src/{core => ipv6rwc}/icmpv6.go (99%) rename src/{core/keystore.go => ipv6rwc/ipv6rwc.go} (77%) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index d6d0d1a6..95d40151 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -29,6 +29,7 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/defaults" "github.com/yggdrasil-network/yggdrasil-go/src/core" + "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" "github.com/yggdrasil-network/yggdrasil-go/src/multicast" "github.com/yggdrasil-network/yggdrasil-go/src/tuntap" "github.com/yggdrasil-network/yggdrasil-go/src/version" @@ -353,7 +354,8 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) { } n.multicast.SetupAdminHandlers(n.admin) // Start the TUN/TAP interface - if err := n.tuntap.Init(&n.core, cfg, logger, nil); err != nil { + rwc := ipv6rwc.NewReadWriteCloser(&n.core) + if err := n.tuntap.Init(rwc, cfg, logger, nil); err != nil { logger.Errorln("An error occurred initialising TUN/TAP:", err) } else if err := n.tuntap.Start(); err != nil { logger.Errorln("An error occurred starting TUN/TAP:", err) diff --git a/src/core/api.go b/src/core/api.go index 05d9f36f..6b219340 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -48,7 +48,7 @@ type Session struct { func (c *Core) GetSelf() Self { var self Self - s := c.pc.PacketConn.Debug.GetSelf() + s := c.PacketConn.PacketConn.Debug.GetSelf() self.Key = s.Key self.Root = s.Root self.Coords = s.Coords @@ -63,7 +63,7 @@ func (c *Core) GetPeers() []Peer { names[info.conn] = info.lname } c.links.mutex.Unlock() - ps := c.pc.PacketConn.Debug.GetPeers() + ps := c.PacketConn.PacketConn.Debug.GetPeers() for _, p := range ps { var info Peer info.Key = p.Key @@ -81,7 +81,7 @@ func (c *Core) GetPeers() []Peer { func (c *Core) GetDHT() []DHTEntry { var dhts []DHTEntry - ds := c.pc.PacketConn.Debug.GetDHT() + ds := c.PacketConn.PacketConn.Debug.GetDHT() for _, d := range ds { var info DHTEntry info.Key = d.Key @@ -94,7 +94,7 @@ func (c *Core) GetDHT() []DHTEntry { func (c *Core) GetPaths() []PathEntry { var paths []PathEntry - ps := c.pc.PacketConn.Debug.GetPaths() + ps := c.PacketConn.PacketConn.Debug.GetPaths() for _, p := range ps { var info PathEntry info.Key = p.Key @@ -106,7 +106,7 @@ func (c *Core) GetPaths() []PathEntry { func (c *Core) GetSessions() []Session { var sessions []Session - ss := c.pc.Debug.GetSessions() + ss := c.PacketConn.Debug.GetSessions() for _, s := range ss { var info Session info.Key = s.Key @@ -239,38 +239,6 @@ func (c *Core) PublicKey() ed25519.PublicKey { return c.public } -func (c *Core) MaxMTU() uint64 { - return c.store.maxSessionMTU() -} - -func (c *Core) SetMTU(mtu uint64) { - if mtu < 1280 { - mtu = 1280 - } - c.store.mutex.Lock() - c.store.mtu = mtu - c.store.mutex.Unlock() -} - -func (c *Core) MTU() uint64 { - c.store.mutex.Lock() - mtu := c.store.mtu - c.store.mutex.Unlock() - return mtu -} - -// Implement io.ReadWriteCloser - -func (c *Core) Read(p []byte) (n int, err error) { - n, err = c.store.readPC(p) - return -} - -func (c *Core) Write(p []byte) (n int, err error) { - n, err = c.store.writePC(p) - return -} - func (c *Core) Close() error { c.Stop() return nil diff --git a/src/core/core.go b/src/core/core.go index 89d49177..ac0ea1f0 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -7,10 +7,12 @@ import ( "errors" "fmt" "io/ioutil" + "net" "net/url" "time" - iw "github.com/Arceliar/ironwood/encrypted" + iwe "github.com/Arceliar/ironwood/encrypted" + iwt "github.com/Arceliar/ironwood/types" "github.com/Arceliar/phony" "github.com/gologme/log" @@ -26,13 +28,12 @@ type Core struct { // We're going to keep our own copy of the provided config - that way we can // guarantee that it will be covered by the mutex phony.Inbox - pc *iw.PacketConn + *iwe.PacketConn config *config.NodeConfig // Config secret ed25519.PrivateKey public ed25519.PublicKey links links proto protoHandler - store keyStore log *log.Logger addPeerTimer *time.Timer ctx context.Context @@ -62,9 +63,8 @@ func (c *Core) _init() error { c.public = c.secret.Public().(ed25519.PublicKey) // TODO check public against current.PublicKey, error if they don't match - c.pc, err = iw.NewPacketConn(c.secret) + c.PacketConn, err = iwe.NewPacketConn(c.secret) c.ctx, c.ctxCancel = context.WithCancel(context.Background()) - c.store.init(c) c.proto.init(c) if err := c.proto.nodeinfo.setNodeInfo(c.config.NodeInfo, c.config.NodeInfoPrivacy); err != nil { return fmt.Errorf("setNodeInfo: %w", err) @@ -168,7 +168,7 @@ func (c *Core) Stop() { func (c *Core) _stop() { c.log.Infoln("Stopping...") c.ctxCancel() - c.pc.Close() + c.PacketConn.Close() // TODO make c.Close() do the right thing (act like c.Stop()) if c.addPeerTimer != nil { c.addPeerTimer.Stop() c.addPeerTimer = nil @@ -181,3 +181,53 @@ func (c *Core) _stop() { */ c.log.Infoln("Stopped") } + +func (c *Core) MTU() uint64 { + const sessionTypeOverhead = 1 + return c.PacketConn.MTU() - sessionTypeOverhead +} + +func (c *Core) ReadFrom(p []byte) (n int, from net.Addr, err error) { + buf := make([]byte, c.PacketConn.MTU(), 65535) + for { + bs := buf + n, from, err = c.PacketConn.ReadFrom(bs) + if err != nil { + return 0, from, err + } + if n == 0 { + continue + } + switch bs[0] { + case typeSessionTraffic: + // This is what we want to handle here + case typeSessionProto: + var key keyArray + copy(key[:], from.(iwt.Addr)) + data := append([]byte(nil), bs[1:n]...) + c.proto.handleProto(nil, key, data) + continue + default: + continue + } + bs = bs[1:n] + copy(p, bs) + if len(p) < len(bs) { + n = len(p) + } else { + n = len(bs) + } + return + } +} + +func (c *Core) WriteTo(p []byte, addr net.Addr) (n int, err error) { + buf := make([]byte, 0, 65535) + buf = append(buf, typeSessionTraffic) + buf = append(buf, p...) + n, err = c.PacketConn.WriteTo(buf, addr) + if n > 0 { + n -= 1 + } + return +} diff --git a/src/core/link.go b/src/core/link.go index 165b18b2..ccab9219 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -230,7 +230,7 @@ func (intf *link) handler() (chan struct{}, error) { intf.links.core.log.Infof("Connected %s: %s, source %s", strings.ToUpper(intf.info.linkType), themString, intf.info.local) // Run the handler - err = intf.links.core.pc.HandleConn(ed25519.PublicKey(intf.info.key[:]), intf.conn) + err = intf.links.core.HandleConn(ed25519.PublicKey(intf.info.key[:]), intf.conn) // TODO don't report an error if it's just a 'use of closed network connection' if err != nil { intf.links.core.log.Infof("Disconnected %s: %s, source %s; error: %s", diff --git a/src/core/nodeinfo.go b/src/core/nodeinfo.go index 30644710..90153118 100644 --- a/src/core/nodeinfo.go +++ b/src/core/nodeinfo.go @@ -129,7 +129,7 @@ func (m *nodeinfo) _sendReq(key keyArray, callback func(nodeinfo NodeInfoPayload if callback != nil { m._addCallback(key, callback) } - _, _ = m.proto.core.pc.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) + _, _ = m.proto.core.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) } func (m *nodeinfo) handleReq(from phony.Actor, key keyArray) { @@ -146,7 +146,7 @@ func (m *nodeinfo) handleRes(from phony.Actor, key keyArray, info NodeInfoPayloa func (m *nodeinfo) _sendRes(key keyArray) { bs := append([]byte{typeSessionProto, typeProtoNodeInfoResponse}, m._getNodeInfo()...) - _, _ = m.proto.core.pc.WriteTo(bs, iwt.Addr(key[:])) + _, _ = m.proto.core.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff diff --git a/src/core/proto.go b/src/core/proto.go index 557ac1d5..f9d12c8a 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -1,6 +1,7 @@ package core import ( + "crypto/ed25519" "encoding/hex" "encoding/json" "errors" @@ -29,6 +30,8 @@ type reqInfo struct { timer *time.Timer // time.AfterFunc cleanup } +type keyArray [ed25519.PublicKeySize]byte + type protoHandler struct { phony.Inbox core *Core @@ -149,7 +152,7 @@ func (p *protoHandler) _handleGetPeersRequest(key keyArray) { for _, pinfo := range peers { tmp := append(bs, pinfo.Key[:]...) const responseOverhead = 2 // 1 debug type, 1 getpeers type - if uint64(len(tmp))+responseOverhead > p.core.store.maxSessionMTU() { + if uint64(len(tmp))+responseOverhead > p.core.MTU() { break } bs = tmp @@ -191,7 +194,7 @@ func (p *protoHandler) _handleGetDHTRequest(key keyArray) { for _, dinfo := range dinfos { tmp := append(bs, dinfo.Key[:]...) const responseOverhead = 2 // 1 debug type, 1 getdht type - if uint64(len(tmp))+responseOverhead > p.core.store.maxSessionMTU() { + if uint64(len(tmp))+responseOverhead > p.core.MTU() { break } bs = tmp @@ -209,7 +212,7 @@ func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) - _, _ = p.core.pc.WriteTo(bs, iwt.Addr(key[:])) + _, _ = p.core.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff diff --git a/src/core/types.go b/src/core/types.go index e325b55e..258563a1 100644 --- a/src/core/types.go +++ b/src/core/types.go @@ -1,12 +1,5 @@ package core -// Out-of-band packet types -const ( - typeKeyDummy = iota // nolint:deadcode,varcheck - typeKeyLookup - typeKeyResponse -) - // In-band packet types const ( typeSessionDummy = iota // nolint:deadcode,varcheck diff --git a/src/core/icmpv6.go b/src/ipv6rwc/icmpv6.go similarity index 99% rename from src/core/icmpv6.go rename to src/ipv6rwc/icmpv6.go index d15fbbcb..8faf1d51 100644 --- a/src/core/icmpv6.go +++ b/src/ipv6rwc/icmpv6.go @@ -1,4 +1,4 @@ -package core +package ipv6rwc // The ICMPv6 module implements functions to easily create ICMPv6 // packets. These functions, when mixed with the built-in Go IPv6 diff --git a/src/core/keystore.go b/src/ipv6rwc/ipv6rwc.go similarity index 77% rename from src/core/keystore.go rename to src/ipv6rwc/ipv6rwc.go index 21fb8459..1c715f0f 100644 --- a/src/core/keystore.go +++ b/src/ipv6rwc/ipv6rwc.go @@ -1,4 +1,4 @@ -package core +package ipv6rwc import ( "crypto/ed25519" @@ -14,14 +14,22 @@ import ( iwt "github.com/Arceliar/ironwood/types" "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/core" ) const keyStoreTimeout = 2 * time.Minute +// Out-of-band packet types +const ( + typeKeyDummy = iota // nolint:deadcode,varcheck + typeKeyLookup + typeKeyResponse +) + type keyArray [ed25519.PublicKeySize]byte type keyStore struct { - core *Core + core *core.Core address address.Address subnet address.Subnet mutex sync.Mutex @@ -45,11 +53,11 @@ type buffer struct { timeout *time.Timer } -func (k *keyStore) init(core *Core) { - k.core = core - k.address = *address.AddrForKey(k.core.public) - k.subnet = *address.SubnetForKey(k.core.public) - if err := k.core.pc.SetOutOfBandHandler(k.oobHandler); err != nil { +func (k *keyStore) init(c *core.Core) { + k.core = c + k.address = *address.AddrForKey(k.core.PublicKey()) + k.subnet = *address.SubnetForKey(k.core.PublicKey()) + if err := k.core.SetOutOfBandHandler(k.oobHandler); err != nil { err = fmt.Errorf("tun.core.SetOutOfBandHander: %w", err) panic(err) } @@ -66,7 +74,7 @@ func (k *keyStore) sendToAddress(addr address.Address, bs []byte) { if info := k.addrToInfo[addr]; info != nil { k.resetTimeout(info) k.mutex.Unlock() - _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) + _, _ = k.core.WriteTo(bs, iwt.Addr(info.key[:])) } else { var buf *buffer if buf = k.addrBuffer[addr]; buf == nil { @@ -95,7 +103,7 @@ func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { if info := k.subnetToInfo[subnet]; info != nil { k.resetTimeout(info) k.mutex.Unlock() - _, _ = k.core.pc.WriteTo(bs, iwt.Addr(info.key[:])) + _, _ = k.core.WriteTo(bs, iwt.Addr(info.key[:])) } else { var buf *buffer if buf = k.subnetBuffer[subnet]; buf == nil { @@ -135,11 +143,11 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.resetTimeout(info) k.mutex.Unlock() if buf := k.addrBuffer[info.address]; buf != nil { - k.core.pc.WriteTo(buf.packet, iwt.Addr(info.key[:])) + k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.addrBuffer, info.address) } if buf := k.subnetBuffer[info.subnet]; buf != nil { - k.core.pc.WriteTo(buf.packet, iwt.Addr(info.key[:])) + k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.subnetBuffer, info.subnet) } } else { @@ -191,46 +199,29 @@ func (k *keyStore) oobHandler(fromKey, toKey ed25519.PublicKey, data []byte) { } func (k *keyStore) sendKeyLookup(partial ed25519.PublicKey) { - sig := ed25519.Sign(k.core.secret, partial[:]) + sig := ed25519.Sign(k.core.PrivateKey(), partial[:]) bs := append([]byte{typeKeyLookup}, sig...) - _ = k.core.pc.SendOutOfBand(partial, bs) + _ = k.core.SendOutOfBand(partial, bs) } func (k *keyStore) sendKeyResponse(dest ed25519.PublicKey) { - sig := ed25519.Sign(k.core.secret, dest[:]) + sig := ed25519.Sign(k.core.PrivateKey(), dest[:]) bs := append([]byte{typeKeyResponse}, sig...) - _ = k.core.pc.SendOutOfBand(dest, bs) -} - -func (k *keyStore) maxSessionMTU() uint64 { - const sessionTypeOverhead = 1 - return k.core.pc.MTU() - sessionTypeOverhead + _ = k.core.SendOutOfBand(dest, bs) } func (k *keyStore) readPC(p []byte) (int, error) { - buf := make([]byte, k.core.pc.MTU(), 65535) + buf := make([]byte, k.core.MTU(), 65535) for { bs := buf - n, from, err := k.core.pc.ReadFrom(bs) + n, from, err := k.core.ReadFrom(bs) if err != nil { return n, err } if n == 0 { continue } - switch bs[0] { - case typeSessionTraffic: - // This is what we want to handle here - case typeSessionProto: - var key keyArray - copy(key[:], from.(iwt.Addr)) - data := append([]byte(nil), bs[1:n]...) - k.core.proto.handleProto(nil, key, data) - continue - default: - continue - } - bs = bs[1:n] + bs = bs[:n] if len(bs) == 0 { continue } @@ -294,15 +285,69 @@ func (k *keyStore) writePC(bs []byte) (int, error) { strErr := fmt.Sprint("incorrect source address: ", net.IP(srcAddr[:]).String()) return 0, errors.New(strErr) } - buf := make([]byte, 1+len(bs), 65535) - buf[0] = typeSessionTraffic - copy(buf[1:], bs) if dstAddr.IsValid() { - k.sendToAddress(dstAddr, buf) + k.sendToAddress(dstAddr, bs) } else if dstSubnet.IsValid() { - k.sendToSubnet(dstSubnet, buf) + k.sendToSubnet(dstSubnet, bs) } else { return 0, errors.New("invalid destination address") } return len(bs), nil } + +// Exported API + +func (k *keyStore) MaxMTU() uint64 { + return k.core.MTU() +} + +func (k *keyStore) SetMTU(mtu uint64) { + if mtu > k.MaxMTU() { + mtu = k.MaxMTU() + } + if mtu < 1280 { + mtu = 1280 + } + k.mutex.Lock() + k.mtu = mtu + k.mutex.Unlock() +} + +func (k *keyStore) MTU() uint64 { + k.mutex.Lock() + mtu := k.mtu + k.mutex.Unlock() + return mtu +} + +type ReadWriteCloser struct { + keyStore +} + +func NewReadWriteCloser(c *core.Core) *ReadWriteCloser { + rwc := new(ReadWriteCloser) + rwc.init(c) + return rwc +} + +func (rwc *ReadWriteCloser) Address() address.Address { + return rwc.address +} + +func (rwc *ReadWriteCloser) Subnet() address.Subnet { + return rwc.subnet +} + +func (rwc *ReadWriteCloser) Read(p []byte) (n int, err error) { + return rwc.readPC(p) +} + +func (rwc *ReadWriteCloser) Write(p []byte) (n int, err error) { + return rwc.writePC(p) +} + +func (rwc *ReadWriteCloser) Close() error { + err := rwc.core.Close() + rwc.core.Stop() + return err +} diff --git a/src/tuntap/iface.go b/src/tuntap/iface.go index e72b091f..f629399a 100644 --- a/src/tuntap/iface.go +++ b/src/tuntap/iface.go @@ -17,7 +17,7 @@ func (tun *TunAdapter) read() { begin := TUN_OFFSET_BYTES end := begin + n bs := buf[begin:end] - if _, err := tun.core.Write(bs); err != nil { + if _, err := tun.rwc.Write(bs); err != nil { tun.log.Debugln("Unable to send packet:", err) } } @@ -27,7 +27,7 @@ func (tun *TunAdapter) write() { var buf [TUN_OFFSET_BYTES + 65535]byte for { bs := buf[TUN_OFFSET_BYTES:] - n, err := tun.core.Read(bs) + n, err := tun.rwc.Read(bs) if err != nil { tun.log.Errorln("Exiting tun writer due to core read error:", err) return diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index dbba018b..4caefe4a 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -21,8 +21,8 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/config" - "github.com/yggdrasil-network/yggdrasil-go/src/core" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" + "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" ) type MTU uint16 @@ -32,7 +32,7 @@ type MTU uint16 // should pass this object to the yggdrasil.SetRouterAdapter() function before // calling yggdrasil.Start(). type TunAdapter struct { - core *core.Core + rwc *ipv6rwc.ReadWriteCloser config *config.NodeConfig log *log.Logger addr address.Address @@ -93,8 +93,8 @@ func MaximumMTU() uint64 { // Init initialises the TUN module. You must have acquired a Listener from // the Yggdrasil core before this point and it must not be in use elsewhere. -func (tun *TunAdapter) Init(core *core.Core, config *config.NodeConfig, log *log.Logger, options interface{}) error { - tun.core = core +func (tun *TunAdapter) Init(rwc *ipv6rwc.ReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { + tun.rwc = rwc tun.config = config tun.log = log return nil @@ -119,9 +119,8 @@ func (tun *TunAdapter) _start() error { if tun.config == nil { return errors.New("no configuration available to TUN") } - pk := tun.core.PublicKey() - tun.addr = *address.AddrForKey(pk) - tun.subnet = *address.SubnetForKey(pk) + tun.addr = tun.rwc.Address() + tun.subnet = tun.rwc.Subnet() addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1) if tun.config.IfName == "none" || tun.config.IfName == "dummy" { tun.log.Debugln("Not starting TUN as ifname is none or dummy") @@ -130,8 +129,8 @@ func (tun *TunAdapter) _start() error { return nil } mtu := tun.config.IfMTU - if tun.core.MaxMTU() < mtu { - mtu = tun.core.MaxMTU() + if tun.rwc.MaxMTU() < mtu { + mtu = tun.rwc.MaxMTU() } if err := tun.setup(tun.config.IfName, addr, mtu); err != nil { return err @@ -139,7 +138,7 @@ func (tun *TunAdapter) _start() error { if tun.MTU() != mtu { tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", tun.config.IfMTU, tun.MTU(), MaximumMTU()) } - tun.core.SetMTU(tun.MTU()) + tun.rwc.SetMTU(tun.MTU()) tun.isOpen = true tun.isEnabled = true go tun.read() From e4ce2c79a9a6430f7145798a9a3e93c544bd869c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 5 Jul 2021 22:26:09 +0100 Subject: [PATCH 054/386] Add LocalAddr to complete net.PacketConn interface --- src/core/core.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/core.go b/src/core/core.go index ac0ea1f0..8c816d2b 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -231,3 +231,7 @@ func (c *Core) WriteTo(p []byte, addr net.Addr) (n int, err error) { } return } + +func (c *Core) LocalAddr() net.Addr { + return iwt.Addr(c.public) +} From e224c02d6d88cfd36a0f8598dccfd4cbd4e1f297 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 5 Jul 2021 22:35:46 +0100 Subject: [PATCH 055/386] Revert "Add LocalAddr to complete net.PacketConn interface" This reverts commit e4ce2c79a9a6430f7145798a9a3e93c544bd869c. --- src/core/core.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/core.go b/src/core/core.go index 8c816d2b..ac0ea1f0 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -231,7 +231,3 @@ func (c *Core) WriteTo(p []byte, addr net.Addr) (n int, err error) { } return } - -func (c *Core) LocalAddr() net.Addr { - return iwt.Addr(c.public) -} From 3704ebf4cbeab2b5818ca545e0bebfce2c7bd10a Mon Sep 17 00:00:00 2001 From: Arceliar Date: Tue, 6 Jul 2021 19:45:12 -0500 Subject: [PATCH 056/386] fix debug rpcs and cleanup core.Close/core.Stop --- src/core/api.go | 5 ----- src/core/core.go | 26 ++++++++++++++++---------- src/core/nodeinfo.go | 4 ++-- src/core/proto.go | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/core/api.go b/src/core/api.go index 6b219340..c312923d 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -239,11 +239,6 @@ func (c *Core) PublicKey() ed25519.PublicKey { return c.public } -func (c *Core) Close() error { - c.Stop() - return nil -} - // Hack to get the admin stuff working, TODO something cleaner type AddHandler interface { diff --git a/src/core/core.go b/src/core/core.go index ac0ea1f0..0332980b 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -161,25 +161,31 @@ func (c *Core) _start(nc *config.NodeConfig, log *log.Logger) error { // Stop shuts down the Yggdrasil node. func (c *Core) Stop() { - phony.Block(c, c._stop) + phony.Block(c, func() { + c.log.Infoln("Stopping...") + c._close() + c.log.Infoln("Stopped") + }) +} + +func (c *Core) Close() error { + var err error + phony.Block(c, func() { + err = c._close() + }) + return err } // This function is unsafe and should only be ran by the core actor. -func (c *Core) _stop() { - c.log.Infoln("Stopping...") +func (c *Core) _close() error { c.ctxCancel() - c.PacketConn.Close() // TODO make c.Close() do the right thing (act like c.Stop()) + err := c.PacketConn.Close() if c.addPeerTimer != nil { c.addPeerTimer.Stop() c.addPeerTimer = nil } _ = c.links.stop() - /* FIXME this deadlocks, need a waitgroup or something to coordinate shutdown - for _, peer := range c.GetPeers() { - c.DisconnectPeer(peer.Port) - } - */ - c.log.Infoln("Stopped") + return err } func (c *Core) MTU() uint64 { diff --git a/src/core/nodeinfo.go b/src/core/nodeinfo.go index 90153118..4ca21d73 100644 --- a/src/core/nodeinfo.go +++ b/src/core/nodeinfo.go @@ -129,7 +129,7 @@ func (m *nodeinfo) _sendReq(key keyArray, callback func(nodeinfo NodeInfoPayload if callback != nil { m._addCallback(key, callback) } - _, _ = m.proto.core.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) + _, _ = m.proto.core.PacketConn.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:])) } func (m *nodeinfo) handleReq(from phony.Actor, key keyArray) { @@ -146,7 +146,7 @@ func (m *nodeinfo) handleRes(from phony.Actor, key keyArray, info NodeInfoPayloa func (m *nodeinfo) _sendRes(key keyArray) { bs := append([]byte{typeSessionProto, typeProtoNodeInfoResponse}, m._getNodeInfo()...) - _, _ = m.proto.core.WriteTo(bs, iwt.Addr(key[:])) + _, _ = m.proto.core.PacketConn.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff diff --git a/src/core/proto.go b/src/core/proto.go index f9d12c8a..e60caeff 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -212,7 +212,7 @@ func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) - _, _ = p.core.WriteTo(bs, iwt.Addr(key[:])) + _, _ = p.core.PacketConn.WriteTo(bs, iwt.Addr(key[:])) } // Admin socket stuff From cd5383f7b799932b2536e4ee82e768558a073ec5 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Wed, 7 Jul 2021 18:36:51 -0500 Subject: [PATCH 057/386] fix core tests --- src/core/core_test.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/core_test.go b/src/core/core_test.go index dd60af21..fcfe2e31 100644 --- a/src/core/core_test.go +++ b/src/core/core_test.go @@ -44,13 +44,11 @@ func CreateAndConnectTwo(t testing.TB, verbose bool) (nodeA *Core, nodeB *Core) if err := nodeA.Start(GenerateConfig(), GetLoggerWithPrefix("A: ", verbose)); err != nil { t.Fatal(err) } - nodeA.SetMTU(1500) nodeB = new(Core) if err := nodeB.Start(GenerateConfig(), GetLoggerWithPrefix("B: ", verbose)); err != nil { t.Fatal(err) } - nodeB.SetMTU(1500) u, err := url.Parse("tcp://" + nodeA.links.tcp.getAddr().String()) if err != nil { @@ -94,7 +92,7 @@ func CreateEchoListener(t testing.TB, nodeA *Core, bufLen int, repeats int) chan buf := make([]byte, bufLen) res := make([]byte, bufLen) for i := 0; i < repeats; i++ { - n, err := nodeA.Read(buf) + n, from, err := nodeA.ReadFrom(buf) if err != nil { t.Error(err) return @@ -106,7 +104,7 @@ func CreateEchoListener(t testing.TB, nodeA *Core, bufLen int, repeats int) chan copy(res, buf) copy(res[8:24], buf[24:40]) copy(res[24:40], buf[8:24]) - _, err = nodeA.Write(res) + _, err = nodeA.WriteTo(res, from) if err != nil { t.Error(err) } @@ -141,12 +139,12 @@ func TestCore_Start_Transfer(t *testing.T) { msg[0] = 0x60 copy(msg[8:24], nodeB.Address()) copy(msg[24:40], nodeA.Address()) - _, err := nodeB.Write(msg) + _, err := nodeB.WriteTo(msg, nodeA.LocalAddr()) if err != nil { t.Fatal(err) } buf := make([]byte, msgLen) - _, err = nodeB.Read(buf) + _, _, err = nodeB.ReadFrom(buf) if err != nil { t.Fatal(err) } @@ -179,12 +177,13 @@ func BenchmarkCore_Start_Transfer(b *testing.B) { b.SetBytes(int64(msgLen)) b.ResetTimer() + addr := nodeA.LocalAddr() for i := 0; i < b.N; i++ { - _, err := nodeB.Write(msg) + _, err := nodeB.WriteTo(msg, addr) if err != nil { b.Fatal(err) } - _, err = nodeB.Read(buf) + _, _, err = nodeB.ReadFrom(buf) if err != nil { b.Fatal(err) } From 04ecdf60453846e0ab397f1a36497bb3b268f2bb Mon Sep 17 00:00:00 2001 From: Timur Demin Date: Tue, 6 Jul 2021 21:24:21 +0500 Subject: [PATCH 058/386] Preallocate memory when deriving address from key This makes src/address.AddrForKey preallocate 32 bytes before starting the address derivation. As benches in syg_go show, reallocating temp takes 20% of the function runtime. --- src/address/address.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/address/address.go b/src/address/address.go index 7add23ac..0e2400ed 100644 --- a/src/address/address.go +++ b/src/address/address.go @@ -64,7 +64,7 @@ func AddrForKey(publicKey ed25519.PublicKey) *Address { buf[idx] = ^buf[idx] } var addr Address - var temp []byte + var temp = make([]byte, 0, 32) done := false ones := byte(0) bits := byte(0) From 6a0ddc20efb5d5e79cc64630d3fdeddb8101149f Mon Sep 17 00:00:00 2001 From: cofob <49928332+cofob@users.noreply.github.com> Date: Wed, 21 Jul 2021 17:57:59 +0700 Subject: [PATCH 059/386] Allow yggdrasil bind to ports <1024 --- contrib/systemd/yggdrasil.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 3002e61b..27d27907 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -10,7 +10,7 @@ Group=yggdrasil ProtectHome=true ProtectSystem=true SyslogIdentifier=yggdrasil -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE ExecStartPre=+-/sbin/modprobe tun ExecStart=/usr/bin/yggdrasil -useconffile /etc/yggdrasil.conf ExecReload=/bin/kill -HUP $MAINPID From d8df9755f2e8c41ee21110f77bc0b0b662f59414 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 28 Jul 2021 22:11:20 +0100 Subject: [PATCH 060/386] Allow specifying TLS SNI with ?sni= in peering URI --- src/core/link.go | 1 + src/core/tcp.go | 1 + src/core/tls.go | 13 ++++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index ccab9219..f753156e 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -98,6 +98,7 @@ func (l *links) call(u *url.URL, sintf string) error { l.tcp.call(pathtokens[0], tcpOpts, sintf) case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer + tcpOpts.tlsSNI = u.Query().Get("sni") l.tcp.call(u.Host, tcpOpts, sintf) default: return errors.New("unknown call scheme: " + u.Scheme) diff --git a/src/core/tcp.go b/src/core/tcp.go index 572fd652..7b1773b8 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -64,6 +64,7 @@ type tcpOptions struct { socksProxyAddr string socksProxyAuth *proxy.Auth socksPeerAddr string + tlsSNI string } func (l *TcpListener) Stop() { diff --git a/src/core/tls.go b/src/core/tls.go index 4c25225b..eb21fcbc 100644 --- a/src/core/tls.go +++ b/src/core/tls.go @@ -77,8 +77,8 @@ func (t *tcptls) init(tcp *tcp) { } } -func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { - config := *t.config +func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.Config { + config := t.config.Clone() config.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) != 1 { return errors.New("tls not exactly 1 cert") @@ -103,11 +103,14 @@ func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { } return nil } - return &config + if serverName != "" { + config.ServerName = serverName + } + return config } func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options) + config := t.configForOptions(options, "") conn := tls.Server(c, config) if err := conn.Handshake(); err != nil { return c, err @@ -116,7 +119,7 @@ func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, err } func (t *tcptls) upgradeDialer(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options) + config := t.configForOptions(options, options.tlsSNI) conn := tls.Client(c, config) if err := conn.Handshake(); err != nil { return c, err From f094cf34bf23bde6d6c8515c79f1ad14ea3a230c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 28 Jul 2021 22:23:33 +0100 Subject: [PATCH 061/386] Set SNI by default if the peering URI contains a DNS name --- src/core/link.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/link.go b/src/core/link.go index f753156e..98a7ab31 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -99,6 +99,13 @@ func (l *links) call(u *url.URL, sintf string) error { case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer tcpOpts.tlsSNI = u.Query().Get("sni") + if tcpOpts.tlsSNI == "" { + // SNI headers must contain hostnames and not IP addresses, so we must make sure + // that we do not populate the SNI with an IP literal. + if host, _, err := net.SplitHostPort(u.Host); err == nil && net.ParseIP(host) == nil { + tcpOpts.tlsSNI = host + } + } l.tcp.call(u.Host, tcpOpts, sintf) default: return errors.New("unknown call scheme: " + u.Scheme) From bbdff033ce29d657c099f73f7946c1d5061a1b9c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 1 Aug 2021 21:36:51 +0100 Subject: [PATCH 062/386] Update SNI code --- src/core/link.go | 14 +++++++++++--- src/core/tls.go | 10 ++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index 98a7ab31..755d38a3 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -98,10 +98,18 @@ func (l *links) call(u *url.URL, sintf string) error { l.tcp.call(pathtokens[0], tcpOpts, sintf) case "tls": tcpOpts.upgrade = l.tcp.tls.forDialer - tcpOpts.tlsSNI = u.Query().Get("sni") + // SNI headers must contain hostnames and not IP addresses, so we must make sure + // that we do not populate the SNI with an IP literal. We do this by splitting + // the host-port combo from the query option and then seeing if it parses to an + // IP address successfully or not. + if sni := u.Query().Get("sni"); sni != "" { + if host, _, err := net.SplitHostPort(sni); err == nil && net.ParseIP(host) == nil { + tcpOpts.tlsSNI = host + } + } + // If the SNI is not configured still because the above failed then we'll try + // again but this time we'll use the host part of the peering URI instead. if tcpOpts.tlsSNI == "" { - // SNI headers must contain hostnames and not IP addresses, so we must make sure - // that we do not populate the SNI with an IP literal. if host, _, err := net.SplitHostPort(u.Host); err == nil && net.ParseIP(host) == nil { tcpOpts.tlsSNI = host } diff --git a/src/core/tls.go b/src/core/tls.go index eb21fcbc..9e340ac4 100644 --- a/src/core/tls.go +++ b/src/core/tls.go @@ -77,7 +77,7 @@ func (t *tcptls) init(tcp *tcp) { } } -func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.Config { +func (t *tcptls) configForOptions(options *tcpOptions) *tls.Config { config := t.config.Clone() config.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) != 1 { @@ -103,14 +103,11 @@ func (t *tcptls) configForOptions(options *tcpOptions, serverName string) *tls.C } return nil } - if serverName != "" { - config.ServerName = serverName - } return config } func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options, "") + config := t.configForOptions(options) conn := tls.Server(c, config) if err := conn.Handshake(); err != nil { return c, err @@ -119,7 +116,8 @@ func (t *tcptls) upgradeListener(c net.Conn, options *tcpOptions) (net.Conn, err } func (t *tcptls) upgradeDialer(c net.Conn, options *tcpOptions) (net.Conn, error) { - config := t.configForOptions(options, options.tlsSNI) + config := t.configForOptions(options) + config.ServerName = options.tlsSNI conn := tls.Client(c, config) if err := conn.Handshake(); err != nil { return c, err From d1cd671bece1c69942f069d059174f01d5565406 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 1 Aug 2021 21:39:49 +0100 Subject: [PATCH 063/386] Fix bug --- src/core/link.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index 755d38a3..8797b886 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -103,8 +103,8 @@ func (l *links) call(u *url.URL, sintf string) error { // the host-port combo from the query option and then seeing if it parses to an // IP address successfully or not. if sni := u.Query().Get("sni"); sni != "" { - if host, _, err := net.SplitHostPort(sni); err == nil && net.ParseIP(host) == nil { - tcpOpts.tlsSNI = host + if net.ParseIP(sni) == nil { + tcpOpts.tlsSNI = sni } } // If the SNI is not configured still because the above failed then we'll try From cbb6dc1b7d16616a27b31befcc5a9cf2b08b62c2 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Tue, 3 Aug 2021 02:47:38 +0500 Subject: [PATCH 064/386] Split yggdrasilctl code into separate functions (refactoring) (#815) * Move yggdrasilctl responses to separate functions * Move yggdrasilctl request switch to separate function * Add empty lines * Create struct CmdLine for yggdrasilctl * Move yggdrasilctl command line parsing to separate func * Turn struct CmdLine into CmdLineEnv * Rename func parseCmdLine to parseFlagsAndArgs * Move yggdrasilctl endpoint setting logic into separate func * Function to create yggdrasilctl CmdLineEnv * Reorder code * Move struct fields into lines * Turn yggdrasilctl CmdLineEnv funcs to methods * Move yggdrasilctl connection code to separate func * Rename functions * Move yggdrasilctl command line env to separate mod * Move yggdrasilctl command line env to main mod * Run goimports Co-authored-by: Neil Alexander --- cmd/yggdrasilctl/cmd_line_env.go | 94 +++++ cmd/yggdrasilctl/main.go | 651 ++++++++++++++++--------------- 2 files changed, 422 insertions(+), 323 deletions(-) create mode 100644 cmd/yggdrasilctl/cmd_line_env.go diff --git a/cmd/yggdrasilctl/cmd_line_env.go b/cmd/yggdrasilctl/cmd_line_env.go new file mode 100644 index 00000000..bd6df8fc --- /dev/null +++ b/cmd/yggdrasilctl/cmd_line_env.go @@ -0,0 +1,94 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + + "github.com/hjson/hjson-go" + "golang.org/x/text/encoding/unicode" + + "github.com/yggdrasil-network/yggdrasil-go/src/defaults" +) + +type CmdLineEnv struct { + args []string + endpoint, server string + injson, verbose, ver bool +} + +func newCmdLineEnv() CmdLineEnv { + var cmdLineEnv CmdLineEnv + cmdLineEnv.endpoint = defaults.GetDefaults().DefaultAdminListen + return cmdLineEnv +} + +func (cmdLineEnv *CmdLineEnv) parseFlagsAndArgs() { + flag.Usage = func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] command [key=value] [key=value] ...\n\n", os.Args[0]) + fmt.Println("Options:") + flag.PrintDefaults() + fmt.Println() + fmt.Println("Please note that options must always specified BEFORE the command\non the command line or they will be ignored.") + fmt.Println() + fmt.Println("Commands:\n - Use \"list\" for a list of available commands") + fmt.Println() + fmt.Println("Examples:") + fmt.Println(" - ", os.Args[0], "list") + fmt.Println(" - ", os.Args[0], "getPeers") + fmt.Println(" - ", os.Args[0], "-v getSelf") + fmt.Println(" - ", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false") + fmt.Println(" - ", os.Args[0], "-endpoint=tcp://localhost:9001 getDHT") + fmt.Println(" - ", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getDHT") + } + + server := flag.String("endpoint", cmdLineEnv.endpoint, "Admin socket endpoint") + injson := flag.Bool("json", false, "Output in JSON format (as opposed to pretty-print)") + verbose := flag.Bool("v", false, "Verbose output (includes public keys)") + ver := flag.Bool("version", false, "Prints the version of this build") + + flag.Parse() + + cmdLineEnv.args = flag.Args() + cmdLineEnv.server = *server + cmdLineEnv.injson = *injson + cmdLineEnv.verbose = *verbose + cmdLineEnv.ver = *ver +} + +func (cmdLineEnv *CmdLineEnv) setEndpoint(logger *log.Logger) { + if cmdLineEnv.server == cmdLineEnv.endpoint { + if config, err := ioutil.ReadFile(defaults.GetDefaults().DefaultConfigFile); err == nil { + if bytes.Equal(config[0:2], []byte{0xFF, 0xFE}) || + bytes.Equal(config[0:2], []byte{0xFE, 0xFF}) { + utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) + decoder := utf.NewDecoder() + config, err = decoder.Bytes(config) + if err != nil { + panic(err) + } + } + var dat map[string]interface{} + if err := hjson.Unmarshal(config, &dat); err != nil { + panic(err) + } + if ep, ok := dat["AdminListen"].(string); ok && (ep != "none" && ep != "") { + cmdLineEnv.endpoint = ep + logger.Println("Found platform default config file", defaults.GetDefaults().DefaultConfigFile) + logger.Println("Using endpoint", cmdLineEnv.endpoint, "from AdminListen") + } else { + logger.Println("Configuration file doesn't contain appropriate AdminListen option") + logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) + } + } else { + logger.Println("Can't open config file from default location", defaults.GetDefaults().DefaultConfigFile) + logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) + } + } else { + cmdLineEnv.endpoint = cmdLineEnv.server + logger.Println("Using endpoint", cmdLineEnv.endpoint, "from command line") + } +} diff --git a/cmd/yggdrasilctl/main.go b/cmd/yggdrasilctl/main.go index 91923392..788b4f19 100644 --- a/cmd/yggdrasilctl/main.go +++ b/cmd/yggdrasilctl/main.go @@ -6,7 +6,6 @@ import ( "errors" "flag" "fmt" - "io/ioutil" "log" "net" "net/url" @@ -15,10 +14,6 @@ import ( "strconv" "strings" - "golang.org/x/text/encoding/unicode" - - "github.com/hjson/hjson-go" - "github.com/yggdrasil-network/yggdrasil-go/src/defaults" "github.com/yggdrasil-network/yggdrasil-go/src/version" ) @@ -32,6 +27,7 @@ func main() { func run() int { logbuffer := &bytes.Buffer{} logger := log.New(logbuffer, "", log.Flags()) + defer func() int { if r := recover(); r != nil { logger.Println("Fatal error:", r) @@ -41,97 +37,24 @@ func run() int { return 0 }() - endpoint := defaults.GetDefaults().DefaultAdminListen + cmdLineEnv := newCmdLineEnv() + cmdLineEnv.parseFlagsAndArgs() - flag.Usage = func() { - fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] command [key=value] [key=value] ...\n\n", os.Args[0]) - fmt.Println("Options:") - flag.PrintDefaults() - fmt.Println() - fmt.Println("Please note that options must always specified BEFORE the command\non the command line or they will be ignored.") - fmt.Println() - fmt.Println("Commands:\n - Use \"list\" for a list of available commands") - fmt.Println() - fmt.Println("Examples:") - fmt.Println(" - ", os.Args[0], "list") - fmt.Println(" - ", os.Args[0], "getPeers") - fmt.Println(" - ", os.Args[0], "-v getSelf") - fmt.Println(" - ", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false") - fmt.Println(" - ", os.Args[0], "-endpoint=tcp://localhost:9001 getDHT") - fmt.Println(" - ", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getDHT") - } - server := flag.String("endpoint", endpoint, "Admin socket endpoint") - injson := flag.Bool("json", false, "Output in JSON format (as opposed to pretty-print)") - verbose := flag.Bool("v", false, "Verbose output (includes public keys)") - ver := flag.Bool("version", false, "Prints the version of this build") - flag.Parse() - args := flag.Args() - - if *ver { + if cmdLineEnv.ver { fmt.Println("Build name:", version.BuildName()) fmt.Println("Build version:", version.BuildVersion()) fmt.Println("To get the version number of the running Yggdrasil node, run", os.Args[0], "getSelf") return 0 } - if len(args) == 0 { + if len(cmdLineEnv.args) == 0 { flag.Usage() return 0 } - if *server == endpoint { - if config, err := ioutil.ReadFile(defaults.GetDefaults().DefaultConfigFile); err == nil { - if bytes.Equal(config[0:2], []byte{0xFF, 0xFE}) || - bytes.Equal(config[0:2], []byte{0xFE, 0xFF}) { - utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) - decoder := utf.NewDecoder() - config, err = decoder.Bytes(config) - if err != nil { - panic(err) - } - } - var dat map[string]interface{} - if err := hjson.Unmarshal(config, &dat); err != nil { - panic(err) - } - if ep, ok := dat["AdminListen"].(string); ok && (ep != "none" && ep != "") { - endpoint = ep - logger.Println("Found platform default config file", defaults.GetDefaults().DefaultConfigFile) - logger.Println("Using endpoint", endpoint, "from AdminListen") - } else { - logger.Println("Configuration file doesn't contain appropriate AdminListen option") - logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) - } - } else { - logger.Println("Can't open config file from default location", defaults.GetDefaults().DefaultConfigFile) - logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen) - } - } else { - endpoint = *server - logger.Println("Using endpoint", endpoint, "from command line") - } + cmdLineEnv.setEndpoint(logger) - var conn net.Conn - u, err := url.Parse(endpoint) - if err == nil { - switch strings.ToLower(u.Scheme) { - case "unix": - logger.Println("Connecting to UNIX socket", endpoint[7:]) - conn, err = net.Dial("unix", endpoint[7:]) - case "tcp": - logger.Println("Connecting to TCP socket", u.Host) - conn, err = net.Dial("tcp", u.Host) - default: - logger.Println("Unknown protocol or malformed address - check your endpoint") - err = errors.New("protocol not supported") - } - } else { - logger.Println("Connecting to TCP socket", u.Host) - conn, err = net.Dial("tcp", endpoint) - } - if err != nil { - panic(err) - } + conn := connect(cmdLineEnv.endpoint, logger) logger.Println("Connected") defer conn.Close() @@ -140,7 +63,7 @@ func run() int { send := make(admin_info) recv := make(admin_info) - for c, a := range args { + for c, a := range cmdLineEnv.args { if c == 0 { if strings.HasPrefix(a, "-") { logger.Printf("Ignoring flag %s as it should be specified before other parameters\n", a) @@ -176,7 +99,9 @@ func run() int { if err := encoder.Encode(&send); err != nil { panic(err) } + logger.Printf("Request sent") + if err := decoder.Decode(&recv); err == nil { logger.Printf("Response received") if recv["status"] == "error" { @@ -195,252 +120,16 @@ func run() int { fmt.Println("Missing response body (malformed response?)") return 1 } - req := recv["request"].(map[string]interface{}) res := recv["response"].(map[string]interface{}) - if *injson { + if cmdLineEnv.injson { if json, err := json.MarshalIndent(res, "", " "); err == nil { fmt.Println(string(json)) } return 0 } - switch strings.ToLower(req["request"].(string)) { - case "dot": - fmt.Println(res["dot"]) - case "list", "getpeers", "getswitchpeers", "getdht", "getsessions", "dhtping": - maxWidths := make(map[string]int) - var keyOrder []string - keysOrdered := false - - for _, tlv := range res { - for slk, slv := range tlv.(map[string]interface{}) { - if !keysOrdered { - for k := range slv.(map[string]interface{}) { - if !*verbose { - if k == "box_pub_key" || k == "box_sig_key" || k == "nodeinfo" || k == "was_mtu_fixed" { - continue - } - } - keyOrder = append(keyOrder, fmt.Sprint(k)) - } - sort.Strings(keyOrder) - keysOrdered = true - } - for k, v := range slv.(map[string]interface{}) { - if len(fmt.Sprint(slk)) > maxWidths["key"] { - maxWidths["key"] = len(fmt.Sprint(slk)) - } - if len(fmt.Sprint(v)) > maxWidths[k] { - maxWidths[k] = len(fmt.Sprint(v)) - if maxWidths[k] < len(k) { - maxWidths[k] = len(k) - } - } - } - } - - if len(keyOrder) > 0 { - fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", "") - for _, v := range keyOrder { - fmt.Printf("%-"+fmt.Sprint(maxWidths[v])+"s ", v) - } - fmt.Println() - } - - for slk, slv := range tlv.(map[string]interface{}) { - fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", slk) - for _, k := range keyOrder { - preformatted := slv.(map[string]interface{})[k] - var formatted string - switch k { - case "bytes_sent", "bytes_recvd": - formatted = fmt.Sprintf("%d", uint(preformatted.(float64))) - case "uptime", "last_seen": - seconds := uint(preformatted.(float64)) % 60 - minutes := uint(preformatted.(float64)/60) % 60 - hours := uint(preformatted.(float64) / 60 / 60) - formatted = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) - default: - formatted = fmt.Sprint(preformatted) - } - fmt.Printf("%-"+fmt.Sprint(maxWidths[k])+"s ", formatted) - } - fmt.Println() - } - } - case "gettuntap", "settuntap": - for k, v := range res { - fmt.Println("Interface name:", k) - if mtu, ok := v.(map[string]interface{})["mtu"].(float64); ok { - fmt.Println("Interface MTU:", mtu) - } - if tap_mode, ok := v.(map[string]interface{})["tap_mode"].(bool); ok { - fmt.Println("TAP mode:", tap_mode) - } - } - case "getself": - for k, v := range res["self"].(map[string]interface{}) { - if buildname, ok := v.(map[string]interface{})["build_name"].(string); ok && buildname != "unknown" { - fmt.Println("Build name:", buildname) - } - if buildversion, ok := v.(map[string]interface{})["build_version"].(string); ok && buildversion != "unknown" { - fmt.Println("Build version:", buildversion) - } - fmt.Println("IPv6 address:", k) - if subnet, ok := v.(map[string]interface{})["subnet"].(string); ok { - fmt.Println("IPv6 subnet:", subnet) - } - if boxSigKey, ok := v.(map[string]interface{})["key"].(string); ok { - fmt.Println("Public key:", boxSigKey) - } - if coords, ok := v.(map[string]interface{})["coords"].(string); ok { - fmt.Println("Coords:", coords) - } - if *verbose { - if nodeID, ok := v.(map[string]interface{})["node_id"].(string); ok { - fmt.Println("Node ID:", nodeID) - } - if boxPubKey, ok := v.(map[string]interface{})["box_pub_key"].(string); ok { - fmt.Println("Public encryption key:", boxPubKey) - } - if boxSigKey, ok := v.(map[string]interface{})["box_sig_key"].(string); ok { - fmt.Println("Public signing key:", boxSigKey) - } - } - } - case "getswitchqueues": - maximumqueuesize := float64(4194304) - portqueues := make(map[float64]float64) - portqueuesize := make(map[float64]float64) - portqueuepackets := make(map[float64]float64) - v := res["switchqueues"].(map[string]interface{}) - if queuecount, ok := v["queues_count"].(float64); ok { - fmt.Printf("Active queue count: %d queues\n", uint(queuecount)) - } - if queuesize, ok := v["queues_size"].(float64); ok { - fmt.Printf("Active queue size: %d bytes\n", uint(queuesize)) - } - if highestqueuecount, ok := v["highest_queues_count"].(float64); ok { - fmt.Printf("Highest queue count: %d queues\n", uint(highestqueuecount)) - } - if highestqueuesize, ok := v["highest_queues_size"].(float64); ok { - fmt.Printf("Highest queue size: %d bytes\n", uint(highestqueuesize)) - } - if m, ok := v["maximum_queues_size"].(float64); ok { - maximumqueuesize = m - fmt.Printf("Maximum queue size: %d bytes\n", uint(maximumqueuesize)) - } - if queues, ok := v["queues"].([]interface{}); ok { - if len(queues) != 0 { - fmt.Println("Active queues:") - for _, v := range queues { - queueport := v.(map[string]interface{})["queue_port"].(float64) - queuesize := v.(map[string]interface{})["queue_size"].(float64) - queuepackets := v.(map[string]interface{})["queue_packets"].(float64) - queueid := v.(map[string]interface{})["queue_id"].(string) - portqueues[queueport]++ - portqueuesize[queueport] += queuesize - portqueuepackets[queueport] += queuepackets - queuesizepercent := (100 / maximumqueuesize) * queuesize - fmt.Printf("- Switch port %d, Stream ID: %v, size: %d bytes (%d%% full), %d packets\n", - uint(queueport), []byte(queueid), uint(queuesize), - uint(queuesizepercent), uint(queuepackets)) - } - } - } - if len(portqueuesize) > 0 && len(portqueuepackets) > 0 { - fmt.Println("Aggregated statistics by switchport:") - for k, v := range portqueuesize { - queuesizepercent := (100 / (portqueues[k] * maximumqueuesize)) * v - fmt.Printf("- Switch port %d, size: %d bytes (%d%% full), %d packets\n", - uint(k), uint(v), uint(queuesizepercent), uint(portqueuepackets[k])) - } - } - case "addpeer", "removepeer", "addallowedencryptionpublickey", "removeallowedencryptionpublickey", "addsourcesubnet", "addroute", "removesourcesubnet", "removeroute": - if _, ok := res["added"]; ok { - for _, v := range res["added"].([]interface{}) { - fmt.Println("Added:", fmt.Sprint(v)) - } - } - if _, ok := res["not_added"]; ok { - for _, v := range res["not_added"].([]interface{}) { - fmt.Println("Not added:", fmt.Sprint(v)) - } - } - if _, ok := res["removed"]; ok { - for _, v := range res["removed"].([]interface{}) { - fmt.Println("Removed:", fmt.Sprint(v)) - } - } - if _, ok := res["not_removed"]; ok { - for _, v := range res["not_removed"].([]interface{}) { - fmt.Println("Not removed:", fmt.Sprint(v)) - } - } - case "getallowedencryptionpublickeys": - if _, ok := res["allowed_box_pubs"]; !ok { - fmt.Println("All connections are allowed") - } else if res["allowed_box_pubs"] == nil { - fmt.Println("All connections are allowed") - } else { - fmt.Println("Connections are allowed only from the following public box keys:") - for _, v := range res["allowed_box_pubs"].([]interface{}) { - fmt.Println("-", v) - } - } - case "getmulticastinterfaces": - if _, ok := res["multicast_interfaces"]; !ok { - fmt.Println("No multicast interfaces found") - } else if res["multicast_interfaces"] == nil { - fmt.Println("No multicast interfaces found") - } else { - fmt.Println("Multicast peer discovery is active on:") - for _, v := range res["multicast_interfaces"].([]interface{}) { - fmt.Println("-", v) - } - } - case "getsourcesubnets": - if _, ok := res["source_subnets"]; !ok { - fmt.Println("No source subnets found") - } else if res["source_subnets"] == nil { - fmt.Println("No source subnets found") - } else { - fmt.Println("Source subnets:") - for _, v := range res["source_subnets"].([]interface{}) { - fmt.Println("-", v) - } - } - case "getroutes": - if routes, ok := res["routes"].(map[string]interface{}); !ok { - fmt.Println("No routes found") - } else { - if res["routes"] == nil || len(routes) == 0 { - fmt.Println("No routes found") - } else { - fmt.Println("Routes:") - for k, v := range routes { - if pv, ok := v.(string); ok { - fmt.Println("-", k, " via ", pv) - } - } - } - } - case "settunnelrouting": - fallthrough - case "gettunnelrouting": - if enabled, ok := res["enabled"].(bool); !ok { - fmt.Println("Tunnel routing is disabled") - } else if !enabled { - fmt.Println("Tunnel routing is disabled") - } else { - fmt.Println("Tunnel routing is enabled") - } - default: - if json, err := json.MarshalIndent(recv["response"], "", " "); err == nil { - fmt.Println(string(json)) - } - } + handleAll(recv, cmdLineEnv.verbose) } else { logger.Println("Error receiving response:", err) } @@ -448,5 +137,321 @@ func run() int { if v, ok := recv["status"]; ok && v != "success" { return 1 } + return 0 } + +func connect(endpoint string, logger *log.Logger) net.Conn { + var conn net.Conn + + u, err := url.Parse(endpoint) + + if err == nil { + switch strings.ToLower(u.Scheme) { + case "unix": + logger.Println("Connecting to UNIX socket", endpoint[7:]) + conn, err = net.Dial("unix", endpoint[7:]) + case "tcp": + logger.Println("Connecting to TCP socket", u.Host) + conn, err = net.Dial("tcp", u.Host) + default: + logger.Println("Unknown protocol or malformed address - check your endpoint") + err = errors.New("protocol not supported") + } + } else { + logger.Println("Connecting to TCP socket", u.Host) + conn, err = net.Dial("tcp", endpoint) + } + + if err != nil { + panic(err) + } + + return conn +} + +func handleAll(recv map[string]interface{}, verbose bool) { + req := recv["request"].(map[string]interface{}) + res := recv["response"].(map[string]interface{}) + + switch strings.ToLower(req["request"].(string)) { + case "dot": + handleDot(res) + case "list", "getpeers", "getswitchpeers", "getdht", "getsessions", "dhtping": + handleVariousInfo(res, verbose) + case "gettuntap", "settuntap": + handleGetAndSetTunTap(res) + case "getself": + handleGetSelf(res, verbose) + case "getswitchqueues": + handleGetSwitchQueues(res) + case "addpeer", "removepeer", "addallowedencryptionpublickey", "removeallowedencryptionpublickey", "addsourcesubnet", "addroute", "removesourcesubnet", "removeroute": + handleAddsAndRemoves(res) + case "getallowedencryptionpublickeys": + handleGetAllowedEncryptionPublicKeys(res) + case "getmulticastinterfaces": + handleGetMulticastInterfaces(res) + case "getsourcesubnets": + handleGetSourceSubnets(res) + case "getroutes": + handleGetRoutes(res) + case "settunnelrouting": + fallthrough + case "gettunnelrouting": + handleGetTunnelRouting(res) + default: + if json, err := json.MarshalIndent(recv["response"], "", " "); err == nil { + fmt.Println(string(json)) + } + } +} + +func handleDot(res map[string]interface{}) { + fmt.Println(res["dot"]) +} + +func handleVariousInfo(res map[string]interface{}, verbose bool) { + maxWidths := make(map[string]int) + var keyOrder []string + keysOrdered := false + + for _, tlv := range res { + for slk, slv := range tlv.(map[string]interface{}) { + if !keysOrdered { + for k := range slv.(map[string]interface{}) { + if !verbose { + if k == "box_pub_key" || k == "box_sig_key" || k == "nodeinfo" || k == "was_mtu_fixed" { + continue + } + } + keyOrder = append(keyOrder, fmt.Sprint(k)) + } + sort.Strings(keyOrder) + keysOrdered = true + } + for k, v := range slv.(map[string]interface{}) { + if len(fmt.Sprint(slk)) > maxWidths["key"] { + maxWidths["key"] = len(fmt.Sprint(slk)) + } + if len(fmt.Sprint(v)) > maxWidths[k] { + maxWidths[k] = len(fmt.Sprint(v)) + if maxWidths[k] < len(k) { + maxWidths[k] = len(k) + } + } + } + } + + if len(keyOrder) > 0 { + fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", "") + for _, v := range keyOrder { + fmt.Printf("%-"+fmt.Sprint(maxWidths[v])+"s ", v) + } + fmt.Println() + } + + for slk, slv := range tlv.(map[string]interface{}) { + fmt.Printf("%-"+fmt.Sprint(maxWidths["key"])+"s ", slk) + for _, k := range keyOrder { + preformatted := slv.(map[string]interface{})[k] + var formatted string + switch k { + case "bytes_sent", "bytes_recvd": + formatted = fmt.Sprintf("%d", uint(preformatted.(float64))) + case "uptime", "last_seen": + seconds := uint(preformatted.(float64)) % 60 + minutes := uint(preformatted.(float64)/60) % 60 + hours := uint(preformatted.(float64) / 60 / 60) + formatted = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) + default: + formatted = fmt.Sprint(preformatted) + } + fmt.Printf("%-"+fmt.Sprint(maxWidths[k])+"s ", formatted) + } + fmt.Println() + } + } +} + +func handleGetAndSetTunTap(res map[string]interface{}) { + for k, v := range res { + fmt.Println("Interface name:", k) + if mtu, ok := v.(map[string]interface{})["mtu"].(float64); ok { + fmt.Println("Interface MTU:", mtu) + } + if tap_mode, ok := v.(map[string]interface{})["tap_mode"].(bool); ok { + fmt.Println("TAP mode:", tap_mode) + } + } +} + +func handleGetSelf(res map[string]interface{}, verbose bool) { + for k, v := range res["self"].(map[string]interface{}) { + if buildname, ok := v.(map[string]interface{})["build_name"].(string); ok && buildname != "unknown" { + fmt.Println("Build name:", buildname) + } + if buildversion, ok := v.(map[string]interface{})["build_version"].(string); ok && buildversion != "unknown" { + fmt.Println("Build version:", buildversion) + } + fmt.Println("IPv6 address:", k) + if subnet, ok := v.(map[string]interface{})["subnet"].(string); ok { + fmt.Println("IPv6 subnet:", subnet) + } + if boxSigKey, ok := v.(map[string]interface{})["key"].(string); ok { + fmt.Println("Public key:", boxSigKey) + } + if coords, ok := v.(map[string]interface{})["coords"].(string); ok { + fmt.Println("Coords:", coords) + } + if verbose { + if nodeID, ok := v.(map[string]interface{})["node_id"].(string); ok { + fmt.Println("Node ID:", nodeID) + } + if boxPubKey, ok := v.(map[string]interface{})["box_pub_key"].(string); ok { + fmt.Println("Public encryption key:", boxPubKey) + } + if boxSigKey, ok := v.(map[string]interface{})["box_sig_key"].(string); ok { + fmt.Println("Public signing key:", boxSigKey) + } + } + } +} + +func handleGetSwitchQueues(res map[string]interface{}) { + maximumqueuesize := float64(4194304) + portqueues := make(map[float64]float64) + portqueuesize := make(map[float64]float64) + portqueuepackets := make(map[float64]float64) + v := res["switchqueues"].(map[string]interface{}) + if queuecount, ok := v["queues_count"].(float64); ok { + fmt.Printf("Active queue count: %d queues\n", uint(queuecount)) + } + if queuesize, ok := v["queues_size"].(float64); ok { + fmt.Printf("Active queue size: %d bytes\n", uint(queuesize)) + } + if highestqueuecount, ok := v["highest_queues_count"].(float64); ok { + fmt.Printf("Highest queue count: %d queues\n", uint(highestqueuecount)) + } + if highestqueuesize, ok := v["highest_queues_size"].(float64); ok { + fmt.Printf("Highest queue size: %d bytes\n", uint(highestqueuesize)) + } + if m, ok := v["maximum_queues_size"].(float64); ok { + maximumqueuesize = m + fmt.Printf("Maximum queue size: %d bytes\n", uint(maximumqueuesize)) + } + if queues, ok := v["queues"].([]interface{}); ok { + if len(queues) != 0 { + fmt.Println("Active queues:") + for _, v := range queues { + queueport := v.(map[string]interface{})["queue_port"].(float64) + queuesize := v.(map[string]interface{})["queue_size"].(float64) + queuepackets := v.(map[string]interface{})["queue_packets"].(float64) + queueid := v.(map[string]interface{})["queue_id"].(string) + portqueues[queueport]++ + portqueuesize[queueport] += queuesize + portqueuepackets[queueport] += queuepackets + queuesizepercent := (100 / maximumqueuesize) * queuesize + fmt.Printf("- Switch port %d, Stream ID: %v, size: %d bytes (%d%% full), %d packets\n", + uint(queueport), []byte(queueid), uint(queuesize), + uint(queuesizepercent), uint(queuepackets)) + } + } + } + if len(portqueuesize) > 0 && len(portqueuepackets) > 0 { + fmt.Println("Aggregated statistics by switchport:") + for k, v := range portqueuesize { + queuesizepercent := (100 / (portqueues[k] * maximumqueuesize)) * v + fmt.Printf("- Switch port %d, size: %d bytes (%d%% full), %d packets\n", + uint(k), uint(v), uint(queuesizepercent), uint(portqueuepackets[k])) + } + } +} + +func handleAddsAndRemoves(res map[string]interface{}) { + if _, ok := res["added"]; ok { + for _, v := range res["added"].([]interface{}) { + fmt.Println("Added:", fmt.Sprint(v)) + } + } + if _, ok := res["not_added"]; ok { + for _, v := range res["not_added"].([]interface{}) { + fmt.Println("Not added:", fmt.Sprint(v)) + } + } + if _, ok := res["removed"]; ok { + for _, v := range res["removed"].([]interface{}) { + fmt.Println("Removed:", fmt.Sprint(v)) + } + } + if _, ok := res["not_removed"]; ok { + for _, v := range res["not_removed"].([]interface{}) { + fmt.Println("Not removed:", fmt.Sprint(v)) + } + } +} + +func handleGetAllowedEncryptionPublicKeys(res map[string]interface{}) { + if _, ok := res["allowed_box_pubs"]; !ok { + fmt.Println("All connections are allowed") + } else if res["allowed_box_pubs"] == nil { + fmt.Println("All connections are allowed") + } else { + fmt.Println("Connections are allowed only from the following public box keys:") + for _, v := range res["allowed_box_pubs"].([]interface{}) { + fmt.Println("-", v) + } + } +} + +func handleGetMulticastInterfaces(res map[string]interface{}) { + if _, ok := res["multicast_interfaces"]; !ok { + fmt.Println("No multicast interfaces found") + } else if res["multicast_interfaces"] == nil { + fmt.Println("No multicast interfaces found") + } else { + fmt.Println("Multicast peer discovery is active on:") + for _, v := range res["multicast_interfaces"].([]interface{}) { + fmt.Println("-", v) + } + } +} + +func handleGetSourceSubnets(res map[string]interface{}) { + if _, ok := res["source_subnets"]; !ok { + fmt.Println("No source subnets found") + } else if res["source_subnets"] == nil { + fmt.Println("No source subnets found") + } else { + fmt.Println("Source subnets:") + for _, v := range res["source_subnets"].([]interface{}) { + fmt.Println("-", v) + } + } +} + +func handleGetRoutes(res map[string]interface{}) { + if routes, ok := res["routes"].(map[string]interface{}); !ok { + fmt.Println("No routes found") + } else { + if res["routes"] == nil || len(routes) == 0 { + fmt.Println("No routes found") + } else { + fmt.Println("Routes:") + for k, v := range routes { + if pv, ok := v.(string); ok { + fmt.Println("-", k, " via ", pv) + } + } + } + } +} + +func handleGetTunnelRouting(res map[string]interface{}) { + if enabled, ok := res["enabled"].(bool); !ok { + fmt.Println("Tunnel routing is disabled") + } else if !enabled { + fmt.Println("Tunnel routing is disabled") + } else { + fmt.Println("Tunnel routing is enabled") + } +} From ebe366ef3bcb1b22a31225b06d140d013e463647 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 7 Aug 2021 10:17:21 +0100 Subject: [PATCH 065/386] Add IPReadWriteCloser interface --- src/tuntap/tun.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 4caefe4a..8676ff99 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -11,6 +11,7 @@ package tuntap import ( "errors" "fmt" + "io" "net" //"sync" @@ -22,17 +23,23 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" - "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" ) -type MTU uint16 +type IPReadWriteCloser interface { + io.ReadWriteCloser + MaxMTU() uint64 + SetMTU(mtu uint64) + MTU() uint64 + Address() address.Address + Subnet() address.Subnet +} // TunAdapter represents a running TUN interface and extends the // yggdrasil.Adapter type. In order to use the TUN adapter with Yggdrasil, you // should pass this object to the yggdrasil.SetRouterAdapter() function before // calling yggdrasil.Start(). type TunAdapter struct { - rwc *ipv6rwc.ReadWriteCloser + rwc IPReadWriteCloser config *config.NodeConfig log *log.Logger addr address.Address @@ -93,7 +100,7 @@ func MaximumMTU() uint64 { // Init initialises the TUN module. You must have acquired a Listener from // the Yggdrasil core before this point and it must not be in use elsewhere. -func (tun *TunAdapter) Init(rwc *ipv6rwc.ReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { +func (tun *TunAdapter) Init(rwc IPReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { tun.rwc = rwc tun.config = config tun.log = log From 3613614b418ddb7d99b931ce0c6a40e89ed04fc8 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 7 Aug 2021 12:56:36 -0500 Subject: [PATCH 066/386] Revert "Add IPReadWriteCloser interface" This reverts commit ebe366ef3bcb1b22a31225b06d140d013e463647. --- src/tuntap/tun.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 8676ff99..4caefe4a 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -11,7 +11,6 @@ package tuntap import ( "errors" "fmt" - "io" "net" //"sync" @@ -23,23 +22,17 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/defaults" + "github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc" ) -type IPReadWriteCloser interface { - io.ReadWriteCloser - MaxMTU() uint64 - SetMTU(mtu uint64) - MTU() uint64 - Address() address.Address - Subnet() address.Subnet -} +type MTU uint16 // TunAdapter represents a running TUN interface and extends the // yggdrasil.Adapter type. In order to use the TUN adapter with Yggdrasil, you // should pass this object to the yggdrasil.SetRouterAdapter() function before // calling yggdrasil.Start(). type TunAdapter struct { - rwc IPReadWriteCloser + rwc *ipv6rwc.ReadWriteCloser config *config.NodeConfig log *log.Logger addr address.Address @@ -100,7 +93,7 @@ func MaximumMTU() uint64 { // Init initialises the TUN module. You must have acquired a Listener from // the Yggdrasil core before this point and it must not be in use elsewhere. -func (tun *TunAdapter) Init(rwc IPReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { +func (tun *TunAdapter) Init(rwc *ipv6rwc.ReadWriteCloser, config *config.NodeConfig, log *log.Logger, options interface{}) error { tun.rwc = rwc tun.config = config tun.log = log From 538ee13669bed5c3637888d0b3ae9e49d833d20c Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Wed, 1 Sep 2021 06:16:57 +0500 Subject: [PATCH 067/386] Add type core.AddHandlerFunc --- src/admin/admin.go | 6 +++--- src/core/api.go | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/admin/admin.go b/src/admin/admin.go index d41a48e1..ce831395 100644 --- a/src/admin/admin.go +++ b/src/admin/admin.go @@ -38,8 +38,8 @@ type AdminSocketResponse struct { } type handler struct { - args []string // List of human-readable argument names - handler func(json.RawMessage) (interface{}, error) // First is input map, second is output + args []string // List of human-readable argument names + handler core.AddHandlerFunc // First is input map, second is output } type ListResponse struct { @@ -51,7 +51,7 @@ type ListEntry struct { } // AddHandler is called for each admin function to add the handler and help documentation to the API. -func (a *AdminSocket) AddHandler(name string, args []string, handlerfunc func(json.RawMessage) (interface{}, error)) error { +func (a *AdminSocket) AddHandler(name string, args []string, handlerfunc core.AddHandlerFunc) error { if _, ok := a.handlers[strings.ToLower(name)]; ok { return errors.New("handler already exists") } diff --git a/src/core/api.go b/src/core/api.go index c312923d..ae13d499 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -242,9 +242,11 @@ func (c *Core) PublicKey() ed25519.PublicKey { // Hack to get the admin stuff working, TODO something cleaner type AddHandler interface { - AddHandler(name string, args []string, handlerfunc func(json.RawMessage) (interface{}, error)) error + AddHandler(name string, args []string, handlerfunc AddHandlerFunc) error } +type AddHandlerFunc func(json.RawMessage) (interface{}, error) + // SetAdmin must be called after Init and before Start. // It sets the admin handler for NodeInfo and the Debug admin functions. func (c *Core) SetAdmin(a AddHandler) error { From a5f2ba80a2d4aecd61f06e85bc1e69995d821f75 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Wed, 1 Sep 2021 06:24:25 +0500 Subject: [PATCH 068/386] Organize code in "src/core/proto.go" --- src/core/proto.go | 83 ++++++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/src/core/proto.go b/src/core/proto.go index e60caeff..da9d9b99 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -34,21 +34,26 @@ type keyArray [ed25519.PublicKeySize]byte type protoHandler struct { phony.Inbox - core *Core + nodeinfo nodeinfo - sreqs map[keyArray]*reqInfo - preqs map[keyArray]*reqInfo - dreqs map[keyArray]*reqInfo + core *Core + + getSelfRequests map[keyArray]*reqInfo + getPeersRequests map[keyArray]*reqInfo + getDHTRequests map[keyArray]*reqInfo } func (p *protoHandler) init(core *Core) { p.core = core p.nodeinfo.init(p) - p.sreqs = make(map[keyArray]*reqInfo) - p.preqs = make(map[keyArray]*reqInfo) - p.dreqs = make(map[keyArray]*reqInfo) + + p.getSelfRequests = make(map[keyArray]*reqInfo) + p.getPeersRequests = make(map[keyArray]*reqInfo) + p.getDHTRequests = make(map[keyArray]*reqInfo) } +// Common functions + func (p *protoHandler) handleProto(from phony.Actor, key keyArray, bs []byte) { if len(bs) == 0 { return @@ -85,22 +90,29 @@ func (p *protoHandler) _handleDebug(key keyArray, bs []byte) { } } +func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { + bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) + _, _ = p.core.PacketConn.WriteTo(bs, iwt.Addr(key[:])) +} + +// Get self + func (p *protoHandler) sendGetSelfRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.sreqs[key]; info != nil { + if info := p.getSelfRequests[key]; info != nil { info.timer.Stop() - delete(p.sreqs, key) + delete(p.getSelfRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.sreqs[key] == info { - delete(p.sreqs, key) + if p.getSelfRequests[key] == info { + delete(p.getSelfRequests, key) } }) }) - p.sreqs[key] = info + p.getSelfRequests[key] = info p._sendDebug(key, typeDebugGetSelfRequest, nil) }) } @@ -119,29 +131,31 @@ func (p *protoHandler) _handleGetSelfRequest(key keyArray) { } func (p *protoHandler) _handleGetSelfResponse(key keyArray, bs []byte) { - if info := p.sreqs[key]; info != nil { + if info := p.getSelfRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.sreqs, key) + delete(p.getSelfRequests, key) } } +// Get peers + func (p *protoHandler) sendGetPeersRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.preqs[key]; info != nil { + if info := p.getPeersRequests[key]; info != nil { info.timer.Stop() - delete(p.preqs, key) + delete(p.getPeersRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.preqs[key] == info { - delete(p.preqs, key) + if p.getPeersRequests[key] == info { + delete(p.getPeersRequests, key) } }) }) - p.preqs[key] = info + p.getPeersRequests[key] = info p._sendDebug(key, typeDebugGetPeersRequest, nil) }) } @@ -161,29 +175,31 @@ func (p *protoHandler) _handleGetPeersRequest(key keyArray) { } func (p *protoHandler) _handleGetPeersResponse(key keyArray, bs []byte) { - if info := p.preqs[key]; info != nil { + if info := p.getPeersRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.preqs, key) + delete(p.getPeersRequests, key) } } +// Get DHT + func (p *protoHandler) sendGetDHTRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.dreqs[key]; info != nil { + if info := p.getDHTRequests[key]; info != nil { info.timer.Stop() - delete(p.dreqs, key) + delete(p.getDHTRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.dreqs[key] == info { - delete(p.dreqs, key) + if p.getDHTRequests[key] == info { + delete(p.getDHTRequests, key) } }) }) - p.dreqs[key] = info + p.getDHTRequests[key] = info p._sendDebug(key, typeDebugGetDHTRequest, nil) }) } @@ -203,19 +219,14 @@ func (p *protoHandler) _handleGetDHTRequest(key keyArray) { } func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { - if info := p.dreqs[key]; info != nil { + if info := p.getDHTRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.dreqs, key) + delete(p.getDHTRequests, key) } } -func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { - bs := append([]byte{typeSessionProto, typeProtoDebug, dType}, data...) - _, _ = p.core.PacketConn.WriteTo(bs, iwt.Addr(key[:])) -} - -// Admin socket stuff +// Admin socket stuff for "Get self" type DebugGetSelfRequest struct { Key string `json:"key"` @@ -255,6 +266,8 @@ func (p *protoHandler) getSelfHandler(in json.RawMessage) (interface{}, error) { } } +// Admin socket stuff for "Get peers" + type DebugGetPeersRequest struct { Key string `json:"key"` } @@ -303,6 +316,8 @@ func (p *protoHandler) getPeersHandler(in json.RawMessage) (interface{}, error) } } +// Admin socket stuff for "Get DHT" + type DebugGetDHTRequest struct { Key string `json:"key"` } From 3c89781057bed6e87daf3f40523c21d0a569d59b Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Wed, 1 Sep 2021 07:57:45 +0500 Subject: [PATCH 069/386] Align and reorder code for lesser diff --- src/core/proto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/proto.go b/src/core/proto.go index da9d9b99..1151d006 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -35,8 +35,8 @@ type keyArray [ed25519.PublicKeySize]byte type protoHandler struct { phony.Inbox + core *Core nodeinfo nodeinfo - core *Core getSelfRequests map[keyArray]*reqInfo getPeersRequests map[keyArray]*reqInfo From 571186ca772e96b1f4226b2dd56252b9aa3e5a30 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Fri, 3 Sep 2021 01:45:30 +0500 Subject: [PATCH 070/386] Rename protohandler attributes --- src/core/proto.go | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/core/proto.go b/src/core/proto.go index 1151d006..3045972e 100644 --- a/src/core/proto.go +++ b/src/core/proto.go @@ -38,18 +38,18 @@ type protoHandler struct { core *Core nodeinfo nodeinfo - getSelfRequests map[keyArray]*reqInfo - getPeersRequests map[keyArray]*reqInfo - getDHTRequests map[keyArray]*reqInfo + selfRequests map[keyArray]*reqInfo + peersRequests map[keyArray]*reqInfo + dhtRequests map[keyArray]*reqInfo } func (p *protoHandler) init(core *Core) { p.core = core p.nodeinfo.init(p) - p.getSelfRequests = make(map[keyArray]*reqInfo) - p.getPeersRequests = make(map[keyArray]*reqInfo) - p.getDHTRequests = make(map[keyArray]*reqInfo) + p.selfRequests = make(map[keyArray]*reqInfo) + p.peersRequests = make(map[keyArray]*reqInfo) + p.dhtRequests = make(map[keyArray]*reqInfo) } // Common functions @@ -99,20 +99,20 @@ func (p *protoHandler) _sendDebug(key keyArray, dType uint8, data []byte) { func (p *protoHandler) sendGetSelfRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.getSelfRequests[key]; info != nil { + if info := p.selfRequests[key]; info != nil { info.timer.Stop() - delete(p.getSelfRequests, key) + delete(p.selfRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.getSelfRequests[key] == info { - delete(p.getSelfRequests, key) + if p.selfRequests[key] == info { + delete(p.selfRequests, key) } }) }) - p.getSelfRequests[key] = info + p.selfRequests[key] = info p._sendDebug(key, typeDebugGetSelfRequest, nil) }) } @@ -131,10 +131,10 @@ func (p *protoHandler) _handleGetSelfRequest(key keyArray) { } func (p *protoHandler) _handleGetSelfResponse(key keyArray, bs []byte) { - if info := p.getSelfRequests[key]; info != nil { + if info := p.selfRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.getSelfRequests, key) + delete(p.selfRequests, key) } } @@ -142,20 +142,20 @@ func (p *protoHandler) _handleGetSelfResponse(key keyArray, bs []byte) { func (p *protoHandler) sendGetPeersRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.getPeersRequests[key]; info != nil { + if info := p.peersRequests[key]; info != nil { info.timer.Stop() - delete(p.getPeersRequests, key) + delete(p.peersRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.getPeersRequests[key] == info { - delete(p.getPeersRequests, key) + if p.peersRequests[key] == info { + delete(p.peersRequests, key) } }) }) - p.getPeersRequests[key] = info + p.peersRequests[key] = info p._sendDebug(key, typeDebugGetPeersRequest, nil) }) } @@ -175,10 +175,10 @@ func (p *protoHandler) _handleGetPeersRequest(key keyArray) { } func (p *protoHandler) _handleGetPeersResponse(key keyArray, bs []byte) { - if info := p.getPeersRequests[key]; info != nil { + if info := p.peersRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.getPeersRequests, key) + delete(p.peersRequests, key) } } @@ -186,20 +186,20 @@ func (p *protoHandler) _handleGetPeersResponse(key keyArray, bs []byte) { func (p *protoHandler) sendGetDHTRequest(key keyArray, callback func([]byte)) { p.Act(nil, func() { - if info := p.getDHTRequests[key]; info != nil { + if info := p.dhtRequests[key]; info != nil { info.timer.Stop() - delete(p.getDHTRequests, key) + delete(p.dhtRequests, key) } info := new(reqInfo) info.callback = callback info.timer = time.AfterFunc(time.Minute, func() { p.Act(nil, func() { - if p.getDHTRequests[key] == info { - delete(p.getDHTRequests, key) + if p.dhtRequests[key] == info { + delete(p.dhtRequests, key) } }) }) - p.getDHTRequests[key] = info + p.dhtRequests[key] = info p._sendDebug(key, typeDebugGetDHTRequest, nil) }) } @@ -219,10 +219,10 @@ func (p *protoHandler) _handleGetDHTRequest(key keyArray) { } func (p *protoHandler) _handleGetDHTResponse(key keyArray, bs []byte) { - if info := p.getDHTRequests[key]; info != nil { + if info := p.dhtRequests[key]; info != nil { info.timer.Stop() info.callback(bs) - delete(p.getDHTRequests, key) + delete(p.dhtRequests, key) } } From 52345a2de49d47bfad23b5cf45435cd84fd971bc Mon Sep 17 00:00:00 2001 From: Fyodor Ustinov Date: Tue, 21 Sep 2021 23:19:25 +0300 Subject: [PATCH 071/386] Check tun.config is not equal to nil before usage (#830) We have to check tun.config is not nil before first use, not after. --- src/tuntap/tun.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 4caefe4a..eddccbcd 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -114,11 +114,11 @@ func (tun *TunAdapter) _start() error { if tun.isOpen { return errors.New("TUN module is already started") } - tun.config.RLock() - defer tun.config.RUnlock() if tun.config == nil { return errors.New("no configuration available to TUN") } + tun.config.RLock() + defer tun.config.RUnlock() tun.addr = tun.rwc.Address() tun.subnet = tun.rwc.Subnet() addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1) From 1c7deb72db461ee4c1ec96137b9242fb6acd1837 Mon Sep 17 00:00:00 2001 From: Paul Dee <647633+systemcrash@users.noreply.github.com> Date: Tue, 21 Sep 2021 22:19:40 +0200 Subject: [PATCH 072/386] Align struct elements to byte boundaries: reduce memory footprint. (#834) --- cmd/yggdrasil/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 95d40151..58b8230d 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -185,14 +185,14 @@ func setLogLevel(loglevel string, logger *log.Logger) { type yggArgs struct { genconf bool useconf bool - useconffile string normaliseconf bool confjson bool autoconf bool ver bool - logto string getaddr bool getsnet bool + useconffile string + logto string loglevel string } From 529a33034becaf0f44fc5b3069fb33f46e4c2bcd Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 23 Sep 2021 04:34:58 -0500 Subject: [PATCH 073/386] gofmt to add new build comments --- src/core/debug.go | 1 + src/core/tcp_darwin.go | 1 + src/core/tcp_linux.go | 1 + src/core/tcp_other.go | 1 + src/defaults/defaults_darwin.go | 1 + src/defaults/defaults_freebsd.go | 1 + src/defaults/defaults_linux.go | 1 + src/defaults/defaults_openbsd.go | 1 + src/defaults/defaults_other.go | 1 + src/defaults/defaults_windows.go | 1 + src/multicast/multicast_darwin.go | 1 + src/multicast/multicast_other.go | 1 + src/multicast/multicast_unix.go | 1 + src/multicast/multicast_windows.go | 1 + src/tuntap/tun_bsd.go | 1 + src/tuntap/tun_darwin.go | 1 + src/tuntap/tun_linux.go | 1 + src/tuntap/tun_other.go | 1 + src/tuntap/tun_windows.go | 1 + 19 files changed, 19 insertions(+) diff --git a/src/core/debug.go b/src/core/debug.go index 0fc08259..eb406798 100644 --- a/src/core/debug.go +++ b/src/core/debug.go @@ -1,3 +1,4 @@ +//go:build debug // +build debug package core diff --git a/src/core/tcp_darwin.go b/src/core/tcp_darwin.go index 6b85c621..2ea3abc8 100644 --- a/src/core/tcp_darwin.go +++ b/src/core/tcp_darwin.go @@ -1,3 +1,4 @@ +//go:build darwin // +build darwin package core diff --git a/src/core/tcp_linux.go b/src/core/tcp_linux.go index 558b4e56..e59c3121 100644 --- a/src/core/tcp_linux.go +++ b/src/core/tcp_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package core diff --git a/src/core/tcp_other.go b/src/core/tcp_other.go index 97b81ed1..8dd76f28 100644 --- a/src/core/tcp_other.go +++ b/src/core/tcp_other.go @@ -1,3 +1,4 @@ +//go:build !darwin && !linux // +build !darwin,!linux package core diff --git a/src/defaults/defaults_darwin.go b/src/defaults/defaults_darwin.go index e16f398f..060ce814 100644 --- a/src/defaults/defaults_darwin.go +++ b/src/defaults/defaults_darwin.go @@ -1,3 +1,4 @@ +//go:build darwin // +build darwin package defaults diff --git a/src/defaults/defaults_freebsd.go b/src/defaults/defaults_freebsd.go index 6c3e1c60..84df48ad 100644 --- a/src/defaults/defaults_freebsd.go +++ b/src/defaults/defaults_freebsd.go @@ -1,3 +1,4 @@ +//go:build freebsd // +build freebsd package defaults diff --git a/src/defaults/defaults_linux.go b/src/defaults/defaults_linux.go index 95c7ae95..c7f5f119 100644 --- a/src/defaults/defaults_linux.go +++ b/src/defaults/defaults_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package defaults diff --git a/src/defaults/defaults_openbsd.go b/src/defaults/defaults_openbsd.go index ef339546..0ec877ca 100644 --- a/src/defaults/defaults_openbsd.go +++ b/src/defaults/defaults_openbsd.go @@ -1,3 +1,4 @@ +//go:build openbsd // +build openbsd package defaults diff --git a/src/defaults/defaults_other.go b/src/defaults/defaults_other.go index d1417322..37637425 100644 --- a/src/defaults/defaults_other.go +++ b/src/defaults/defaults_other.go @@ -1,3 +1,4 @@ +//go:build !linux && !darwin && !windows && !openbsd && !freebsd // +build !linux,!darwin,!windows,!openbsd,!freebsd package defaults diff --git a/src/defaults/defaults_windows.go b/src/defaults/defaults_windows.go index e81d09cf..c1ea9689 100644 --- a/src/defaults/defaults_windows.go +++ b/src/defaults/defaults_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package defaults diff --git a/src/multicast/multicast_darwin.go b/src/multicast/multicast_darwin.go index e7075c0a..7ad0c543 100644 --- a/src/multicast/multicast_darwin.go +++ b/src/multicast/multicast_darwin.go @@ -1,3 +1,4 @@ +//go:build darwin // +build darwin package multicast diff --git a/src/multicast/multicast_other.go b/src/multicast/multicast_other.go index dfcf625f..9977951c 100644 --- a/src/multicast/multicast_other.go +++ b/src/multicast/multicast_other.go @@ -1,3 +1,4 @@ +//go:build !linux && !darwin && !netbsd && !freebsd && !openbsd && !dragonflybsd && !windows // +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows package multicast diff --git a/src/multicast/multicast_unix.go b/src/multicast/multicast_unix.go index 1ff48b17..9c822fcf 100644 --- a/src/multicast/multicast_unix.go +++ b/src/multicast/multicast_unix.go @@ -1,3 +1,4 @@ +//go:build linux || netbsd || freebsd || openbsd || dragonflybsd // +build linux netbsd freebsd openbsd dragonflybsd package multicast diff --git a/src/multicast/multicast_windows.go b/src/multicast/multicast_windows.go index 3666faaa..515412a4 100644 --- a/src/multicast/multicast_windows.go +++ b/src/multicast/multicast_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package multicast diff --git a/src/tuntap/tun_bsd.go b/src/tuntap/tun_bsd.go index 75158857..fe36266b 100644 --- a/src/tuntap/tun_bsd.go +++ b/src/tuntap/tun_bsd.go @@ -1,3 +1,4 @@ +//go:build openbsd || freebsd // +build openbsd freebsd package tuntap diff --git a/src/tuntap/tun_darwin.go b/src/tuntap/tun_darwin.go index 75938881..6f6e2528 100644 --- a/src/tuntap/tun_darwin.go +++ b/src/tuntap/tun_darwin.go @@ -1,3 +1,4 @@ +//go:build !mobile // +build !mobile package tuntap diff --git a/src/tuntap/tun_linux.go b/src/tuntap/tun_linux.go index 0a845368..f849c00f 100644 --- a/src/tuntap/tun_linux.go +++ b/src/tuntap/tun_linux.go @@ -1,3 +1,4 @@ +//go:build !mobile // +build !mobile package tuntap diff --git a/src/tuntap/tun_other.go b/src/tuntap/tun_other.go index c0321267..8ce24953 100644 --- a/src/tuntap/tun_other.go +++ b/src/tuntap/tun_other.go @@ -1,3 +1,4 @@ +//go:build !linux && !darwin && !windows && !openbsd && !freebsd && !mobile // +build !linux,!darwin,!windows,!openbsd,!freebsd,!mobile package tuntap diff --git a/src/tuntap/tun_windows.go b/src/tuntap/tun_windows.go index 7b7ee710..8dce7274 100644 --- a/src/tuntap/tun_windows.go +++ b/src/tuntap/tun_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package tuntap From 86e5306eec42324a7e68b4a5e37b7b9d89e98c83 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 23 Sep 2021 04:35:31 -0500 Subject: [PATCH 074/386] fix race from mutex that wasn't held long enough --- src/ipv6rwc/ipv6rwc.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ipv6rwc/ipv6rwc.go b/src/ipv6rwc/ipv6rwc.go index 1c715f0f..f71c638e 100644 --- a/src/ipv6rwc/ipv6rwc.go +++ b/src/ipv6rwc/ipv6rwc.go @@ -129,6 +129,7 @@ func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.mutex.Lock() + defer k.mutex.Unlock() var kArray keyArray copy(kArray[:], key) var info *keyInfo @@ -140,8 +141,6 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.keyToInfo[info.key] = info k.addrToInfo[info.address] = info k.subnetToInfo[info.subnet] = info - k.resetTimeout(info) - k.mutex.Unlock() if buf := k.addrBuffer[info.address]; buf != nil { k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.addrBuffer, info.address) @@ -150,10 +149,8 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) delete(k.subnetBuffer, info.subnet) } - } else { - k.resetTimeout(info) - k.mutex.Unlock() } + k.resetTimeout(info) return info } From e5d638ff4bdd1bf9847e6e645b658b14f60278ae Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 23 Sep 2021 04:39:12 -0500 Subject: [PATCH 075/386] better way to empty ipv6rwc buffer --- src/ipv6rwc/ipv6rwc.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ipv6rwc/ipv6rwc.go b/src/ipv6rwc/ipv6rwc.go index f71c638e..fc2a688f 100644 --- a/src/ipv6rwc/ipv6rwc.go +++ b/src/ipv6rwc/ipv6rwc.go @@ -129,10 +129,10 @@ func (k *keyStore) sendToSubnet(subnet address.Subnet, bs []byte) { func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.mutex.Lock() - defer k.mutex.Unlock() var kArray keyArray copy(kArray[:], key) var info *keyInfo + var packets [][]byte if info = k.keyToInfo[kArray]; info == nil { info = new(keyInfo) info.key = kArray @@ -142,15 +142,19 @@ func (k *keyStore) update(key ed25519.PublicKey) *keyInfo { k.addrToInfo[info.address] = info k.subnetToInfo[info.subnet] = info if buf := k.addrBuffer[info.address]; buf != nil { - k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) + packets = append(packets, buf.packet) delete(k.addrBuffer, info.address) } if buf := k.subnetBuffer[info.subnet]; buf != nil { - k.core.WriteTo(buf.packet, iwt.Addr(info.key[:])) + packets = append(packets, buf.packet) delete(k.subnetBuffer, info.subnet) } } k.resetTimeout(info) + k.mutex.Unlock() + for _, packet := range packets { + k.core.WriteTo(packet, iwt.Addr(info.key[:])) + } return info } From 9a1d1df85edb5442ec75382334fd5a265382800f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 23 Sep 2021 12:11:03 +0100 Subject: [PATCH 076/386] Use newer Xcode image for macOS builds in CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ebd26e2..fa49c34d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -105,7 +105,7 @@ jobs: build-macos: macos: - xcode: "10.0.0" + xcode: "13.0.0" working_directory: ~/go/src/github.com/yggdrasil-network/yggdrasil-go From 99227b60cedfb278b1b6d6ac9ae965f47fce5ccf Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 28 Sep 2021 11:02:15 +0100 Subject: [PATCH 077/386] Update CI to use Go 1.17, produce Apple Silicon builds (closes #844) --- .circleci/config.yml | 16 ++++--- contrib/macos/create-pkg.sh | 4 ++ src/multicast/multicast_darwin.go | 40 ++-------------- src/multicast/multicast_darwin_cgo.go | 69 +++++++++++++++++++++++++++ src/multicast/multicast_other.go | 4 +- 5 files changed, 89 insertions(+), 44 deletions(-) create mode 100644 src/multicast/multicast_darwin_cgo.go diff --git a/.circleci/config.yml b/.circleci/config.yml index fa49c34d..065f2b0b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ version: 2.1 jobs: lint: docker: - - image: circleci/golang:1.16 + - image: circleci/golang:1.17 steps: - checkout @@ -23,7 +23,7 @@ jobs: build-linux: docker: - - image: circleci/golang:1.16 + - image: circleci/golang:1.17 steps: - checkout @@ -124,11 +124,11 @@ jobs: echo -e "Host *\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - run: - name: Install Go 1.16 + name: Install Go 1.17 command: | cd /tmp - curl -LO https://dl.google.com/go/go1.16.darwin-amd64.pkg - sudo installer -pkg /tmp/go1.16.darwin-amd64.pkg -target / + curl -LO https://dl.google.com/go/go1.17.darwin-amd64.pkg + sudo installer -pkg /tmp/go1.17.darwin-amd64.pkg -target / #- run: # name: Install Gomobile @@ -142,11 +142,15 @@ jobs: GO111MODULE=on GOOS=darwin GOARCH=amd64 ./build cp yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-amd64 cp yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-darwin-amd64; + GO111MODULE=on GOOS=darwin GOARCH=arm64 ./build + cp yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-arm64 + cp yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-darwin-arm64; - run: name: Build for macOS (.pkg format) command: | PKGARCH=amd64 sh contrib/macos/create-pkg.sh + PKGARCH=arm64 sh contrib/macos/create-pkg.sh mv *.pkg /tmp/upload/ #- run: @@ -164,7 +168,7 @@ jobs: build-other: docker: - - image: circleci/golang:1.16 + - image: circleci/golang:1.17 steps: - checkout diff --git a/contrib/macos/create-pkg.sh b/contrib/macos/create-pkg.sh index cc9a74f7..919c45ed 100755 --- a/contrib/macos/create-pkg.sh +++ b/contrib/macos/create-pkg.sh @@ -15,6 +15,10 @@ command -v mkbom >/dev/null 2>&1 || ( sudo make install || (echo "Failed to build mkbom"; exit 1) ) +# Build Yggdrasil +echo "running GO111MODULE=on GOOS=darwin GOARCH=${PKGARCH-amd64} ./build" +GO111MODULE=on GOOS=darwin GOARCH=${PKGARCH-amd64} ./build + # Check if we can find the files we need - they should # exist if you are running this script from the root of # the yggdrasil-go repo and you have ran ./build diff --git a/src/multicast/multicast_darwin.go b/src/multicast/multicast_darwin.go index 7ad0c543..22cf3998 100644 --- a/src/multicast/multicast_darwin.go +++ b/src/multicast/multicast_darwin.go @@ -1,49 +1,17 @@ -//go:build darwin -// +build darwin +//go:build !cgo && (darwin || ios) +// +build !cgo +// +build darwin ios package multicast -/* -#cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation -#import -NSNetServiceBrowser *serviceBrowser; -void StartAWDLBrowsing() { - if (serviceBrowser == nil) { - serviceBrowser = [[NSNetServiceBrowser alloc] init]; - serviceBrowser.includesPeerToPeer = YES; - } - [serviceBrowser searchForServicesOfType:@"_yggdrasil._tcp" inDomain:@""]; -} -void StopAWDLBrowsing() { - if (serviceBrowser == nil) { - return; - } - [serviceBrowser stop]; -} -*/ -import "C" import ( "syscall" - "time" "golang.org/x/sys/unix" ) func (m *Multicast) _multicastStarted() { - if !m.isOpen { - return - } - C.StopAWDLBrowsing() - for intf := range m._interfaces { - if intf == "awdl0" { - C.StartAWDLBrowsing() - break - } - } - time.AfterFunc(time.Minute, func() { - m.Act(nil, m._multicastStarted) - }) + } func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error { diff --git a/src/multicast/multicast_darwin_cgo.go b/src/multicast/multicast_darwin_cgo.go new file mode 100644 index 00000000..b7d7358c --- /dev/null +++ b/src/multicast/multicast_darwin_cgo.go @@ -0,0 +1,69 @@ +//go:build (darwin && cgo) || (ios && cgo) +// +build darwin,cgo ios,cgo + +package multicast + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation +#import +NSNetServiceBrowser *serviceBrowser; +void StartAWDLBrowsing() { + if (serviceBrowser == nil) { + serviceBrowser = [[NSNetServiceBrowser alloc] init]; + serviceBrowser.includesPeerToPeer = YES; + } + [serviceBrowser searchForServicesOfType:@"_yggdrasil._tcp" inDomain:@""]; +} +void StopAWDLBrowsing() { + if (serviceBrowser == nil) { + return; + } + [serviceBrowser stop]; +} +*/ +import "C" +import ( + "syscall" + "time" + + "golang.org/x/sys/unix" +) + +func (m *Multicast) _multicastStarted() { + if !m.isOpen { + return + } + C.StopAWDLBrowsing() + for intf := range m._interfaces { + if intf == "awdl0" { + C.StartAWDLBrowsing() + break + } + } + time.AfterFunc(time.Minute, func() { + m.Act(nil, m._multicastStarted) + }) +} + +func (m *Multicast) 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/multicast/multicast_other.go b/src/multicast/multicast_other.go index 9977951c..263f4ffc 100644 --- a/src/multicast/multicast_other.go +++ b/src/multicast/multicast_other.go @@ -1,5 +1,5 @@ -//go:build !linux && !darwin && !netbsd && !freebsd && !openbsd && !dragonflybsd && !windows -// +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows +//go:build !linux && !darwin && !ios && !netbsd && !freebsd && !openbsd && !dragonflybsd && !windows +// +build !linux,!darwin,!ios,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows package multicast From 4859accbb038f8db3c3a541d0f3f3f76de75b9fb Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 2 Nov 2021 18:03:16 +0000 Subject: [PATCH 078/386] Fix panic in `address.GetKey()` (fixes #860) --- src/address/address.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/address/address.go b/src/address/address.go index 0e2400ed..c7f2eb46 100644 --- a/src/address/address.go +++ b/src/address/address.go @@ -129,7 +129,11 @@ func (a *Address) GetKey() ed25519.PublicKey { bits <<= byte(idx % 8) keyIdx := keyOffset + (idx - addrOffset) bits >>= byte(keyIdx % 8) - key[keyIdx/8] |= bits + idx := keyIdx / 8 + if idx >= len(key) { + break + } + key[idx] |= bits } for idx := range key { key[idx] = ^key[idx] From 5c19f3f88c6b664456721a933c4e37c85214504d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 10:33:00 +0000 Subject: [PATCH 079/386] Update dependencies --- go.mod | 11 +++++------ go.sum | 52 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 398504cb..05044531 100644 --- a/go.mod +++ b/go.mod @@ -17,10 +17,9 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect - golang.org/x/net v0.0.0-20210610132358-84b48f89b13b - golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 - golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f - golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 - golang.zx2c4.com/wireguard/windows v0.3.14 + golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 + golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 + golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b + golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a + golang.zx2c4.com/wireguard/windows v0.4.12 ) diff --git a/go.sum b/go.sum index 5d11fad6..e6df746b 100644 --- a/go.sum +++ b/go.sum @@ -38,42 +38,54 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 h1:VrJZAjbekhoRn7n5FBujY31gboH+iB3pdLxn3gE9FjU= +golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ= -golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 h1:7zYaz3tjChtpayGDzu6H0hDAUM5zIGA2XW7kRNgQ0jc= +golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= -golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0= +golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= -golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 h1:wfOOSvHgIzTZ9h5Vb6yUFZNn7uf3bT7PeYsHOO7tYDM= -golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= -golang.zx2c4.com/wireguard/windows v0.3.14 h1:5yIDYyrQyGkLqV+tzY4ilMNeIvQeMXAz0glZz9u179A= -golang.zx2c4.com/wireguard/windows v0.3.14/go.mod h1:3P4IEAsb+BjlKZmpUXgy74c0iX9AVwwr3WcVJ8nPgME= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard v0.0.0-20211012062646-82d2aa87aa62/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= +golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a h1:tTbyylK9/D3u/wEP26Vx7L700UpY48nhioJWZM1vhZw= +golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= +golang.zx2c4.com/wireguard/windows v0.4.12 h1:CUmbdWKVNzTSsVb4yUAiEwL3KsabdJkEPdDjCHxBlhA= +golang.zx2c4.com/wireguard/windows v0.4.12/go.mod h1:PW4y+d9oY83XU9rRwRwrJDwEMuhVjMxu2gfD1cfzS7w= From 4f3117d81d76d5219063016e458c4d2f748ff05d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 17:40:06 +0000 Subject: [PATCH 080/386] Use `network-online.target` instead of `network.target` for systemd service unit --- contrib/systemd/yggdrasil.service | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 27d27907..f8c2dd22 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -1,8 +1,8 @@ [Unit] Description=yggdrasil -Wants=network.target +Wants=network-online.target Wants=yggdrasil-default-config.service -After=network.target +After=network-online.target After=yggdrasil-default-config.service [Service] From 1f64319712a83aaa7f79789ab247db9542b04dbf Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 17:53:35 +0000 Subject: [PATCH 081/386] Version 0.4.1 --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdb634f3..05291f85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.4.1] - 2021-11-03 +### Added +- TLS peerings now support Server Name Indication (SNI) + - The SNI is sent automatically if the peering URI contains a DNS name + - A custom SNI can be specified by adding the `?sni=domain.com` parameter to the peering URI +- A new `ipv6rwc` API package now implements the IPv6-specific logic separate from the `tun` package + +### Fixed +- A crash when calculating the partial public key for very high IPv6 addresses has been fixed +- A crash due to a concurrent map write has been fixed +- A crash due to missing TUN configuration has been fixed +- A race condition in the keystore code has been fixed + ## [0.4.0] - 2021-07-04 ### Added - New routing scheme, which is backwards incompatible with previous versions of Yggdrasil From 03a5cce5bb739d5f3ad5d9877c38817cf88eccd5 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 20:03:27 +0000 Subject: [PATCH 082/386] Revert Wireguard update This reverts commit 5c19f3f88c6b664456721a933c4e37c85214504d. --- go.mod | 11 ++++++----- go.sum | 52 ++++++++++++++++++++-------------------------------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index 05044531..398504cb 100644 --- a/go.mod +++ b/go.mod @@ -17,9 +17,10 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect - golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 - golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 - golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b - golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a - golang.zx2c4.com/wireguard/windows v0.4.12 + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect + golang.org/x/net v0.0.0-20210610132358-84b48f89b13b + golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 + golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f + golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 + golang.zx2c4.com/wireguard/windows v0.3.14 ) diff --git a/go.sum b/go.sum index e6df746b..5d11fad6 100644 --- a/go.sum +++ b/go.sum @@ -38,54 +38,42 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 h1:VrJZAjbekhoRn7n5FBujY31gboH+iB3pdLxn3gE9FjU= -golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 h1:7zYaz3tjChtpayGDzu6H0hDAUM5zIGA2XW7kRNgQ0jc= -golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0= -golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= +golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/wireguard v0.0.0-20211012062646-82d2aa87aa62/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= -golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a h1:tTbyylK9/D3u/wEP26Vx7L700UpY48nhioJWZM1vhZw= -golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU= -golang.zx2c4.com/wireguard/windows v0.4.12 h1:CUmbdWKVNzTSsVb4yUAiEwL3KsabdJkEPdDjCHxBlhA= -golang.zx2c4.com/wireguard/windows v0.4.12/go.mod h1:PW4y+d9oY83XU9rRwRwrJDwEMuhVjMxu2gfD1cfzS7w= +golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= +golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 h1:wfOOSvHgIzTZ9h5Vb6yUFZNn7uf3bT7PeYsHOO7tYDM= +golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= +golang.zx2c4.com/wireguard/windows v0.3.14 h1:5yIDYyrQyGkLqV+tzY4ilMNeIvQeMXAz0glZz9u179A= +golang.zx2c4.com/wireguard/windows v0.3.14/go.mod h1:3P4IEAsb+BjlKZmpUXgy74c0iX9AVwwr3WcVJ8nPgME= From e4e58831bf6b3d2a194c12c4e8dc3fd7351e6165 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 3 Nov 2021 22:16:53 +0000 Subject: [PATCH 083/386] Version 0.4.2 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05291f85..bb418b11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.4.2] - 2021-11-03 +### Fixed +- Reverted a dependency update which resulted in problems building with Go 1.16 and running on Windows + ## [0.4.1] - 2021-11-03 ### Added - TLS peerings now support Server Name Indication (SNI) From 87e936195ebaa1d11475d6fb3a73958c654be977 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Thu, 4 Nov 2021 13:05:53 +0500 Subject: [PATCH 084/386] Add some tests (#828) * Add tests * Add tests * Add tests * Add tests * Fix code style * Remove unnecessary tests --- src/address/address_test.go | 114 ++++++++++++++++++++++++++++++++++++ src/config/config_test.go | 54 +++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 src/address/address_test.go create mode 100644 src/config/config_test.go diff --git a/src/address/address_test.go b/src/address/address_test.go new file mode 100644 index 00000000..a7939e0f --- /dev/null +++ b/src/address/address_test.go @@ -0,0 +1,114 @@ +package address + +import ( + "bytes" + "crypto/ed25519" + "math/rand" + "testing" +) + +func TestAddress_Address_IsValid(t *testing.T) { + var address Address + rand.Read(address[:]) + + address[0] = 0 + + if address.IsValid() { + t.Fatal("invalid address marked as valid") + } + + address[0] = 0x03 + + if address.IsValid() { + t.Fatal("invalid address marked as valid") + } + + address[0] = 0x02 + + if !address.IsValid() { + t.Fatal("valid address marked as invalid") + } +} + +func TestAddress_Subnet_IsValid(t *testing.T) { + var subnet Subnet + rand.Read(subnet[:]) + + subnet[0] = 0 + + if subnet.IsValid() { + t.Fatal("invalid subnet marked as valid") + } + + subnet[0] = 0x02 + + if subnet.IsValid() { + t.Fatal("invalid subnet marked as valid") + } + + subnet[0] = 0x03 + + if !subnet.IsValid() { + t.Fatal("valid subnet marked as invalid") + } +} + +func TestAddress_AddrForKey(t *testing.T) { + publicKey := ed25519.PublicKey{ + 189, 186, 207, 216, 34, 64, 222, 61, 205, 18, 57, 36, 203, 181, 82, 86, + 251, 141, 171, 8, 170, 152, 227, 5, 82, 138, 184, 79, 65, 158, 110, 251, + } + + expectedAddress := Address{ + 2, 0, 132, 138, 96, 79, 187, 126, 67, 132, 101, 219, 141, 182, 104, 149, + } + + if *AddrForKey(publicKey) != expectedAddress { + t.Fatal("invalid address returned") + } +} + +func TestAddress_SubnetForKey(t *testing.T) { + publicKey := ed25519.PublicKey{ + 189, 186, 207, 216, 34, 64, 222, 61, 205, 18, 57, 36, 203, 181, 82, 86, + 251, 141, 171, 8, 170, 152, 227, 5, 82, 138, 184, 79, 65, 158, 110, 251, + } + + expectedSubnet := Subnet{3, 0, 132, 138, 96, 79, 187, 126} + + if *SubnetForKey(publicKey) != expectedSubnet { + t.Fatal("invalid subnet returned") + } +} + +func TestAddress_Address_GetKey(t *testing.T) { + address := Address{ + 2, 0, 132, 138, 96, 79, 187, 126, 67, 132, 101, 219, 141, 182, 104, 149, + } + + expectedPublicKey := ed25519.PublicKey{ + 189, 186, 207, 216, 34, 64, 222, 61, + 205, 18, 57, 36, 203, 181, 127, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + } + + if !bytes.Equal(address.GetKey(), expectedPublicKey) { + t.Fatal("invalid public key returned") + } +} + +func TestAddress_Subnet_GetKey(t *testing.T) { + subnet := Subnet{3, 0, 132, 138, 96, 79, 187, 126} + + expectedPublicKey := ed25519.PublicKey{ + 189, 186, 207, 216, 34, 64, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + } + + if !bytes.Equal(subnet.GetKey(), expectedPublicKey) { + t.Fatal("invalid public key returned") + } +} diff --git a/src/config/config_test.go b/src/config/config_test.go new file mode 100644 index 00000000..8b6e14e1 --- /dev/null +++ b/src/config/config_test.go @@ -0,0 +1,54 @@ +package config + +import ( + "bytes" + "encoding/hex" + "testing" +) + +func TestConfig_Keys(t *testing.T) { + var nodeConfig NodeConfig + nodeConfig.NewKeys() + + publicKey1, err := hex.DecodeString(nodeConfig.PublicKey) + + if err != nil { + t.Fatal("can not decode generated public key") + } + + if len(publicKey1) == 0 { + t.Fatal("empty public key generated") + } + + privateKey1, err := hex.DecodeString(nodeConfig.PrivateKey) + + if err != nil { + t.Fatal("can not decode generated private key") + } + + if len(privateKey1) == 0 { + t.Fatal("empty private key generated") + } + + nodeConfig.NewKeys() + + publicKey2, err := hex.DecodeString(nodeConfig.PublicKey) + + if err != nil { + t.Fatal("can not decode generated public key") + } + + if bytes.Equal(publicKey2, publicKey1) { + t.Fatal("same public key generated") + } + + privateKey2, err := hex.DecodeString(nodeConfig.PrivateKey) + + if err != nil { + t.Fatal("can not decode generated private key") + } + + if bytes.Equal(privateKey2, privateKey1) { + t.Fatal("same private key generated") + } +} From 408d381591e99c273bf8db520a185478cdd8024f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 6 Dec 2021 11:19:58 +0000 Subject: [PATCH 085/386] Set `hostArchitectures` in macOS `.pkg` installer --- contrib/macos/create-pkg.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/macos/create-pkg.sh b/contrib/macos/create-pkg.sh index 919c45ed..773f01ee 100755 --- a/contrib/macos/create-pkg.sh +++ b/contrib/macos/create-pkg.sh @@ -79,6 +79,7 @@ PKGNAME=$(sh contrib/semver/name.sh) PKGVERSION=$(sh contrib/semver/version.sh --bare) PKGARCH=${PKGARCH-amd64} PAYLOADSIZE=$(( $(wc -c pkgbuild/flat/base.pkg/Payload | awk '{ print $1 }') / 1024 )) +[ "$PKGARCH" = "amd64" ] && PKGHOSTARCH="x86_64" || PKGHOSTARCH=${PKGARCH} # Create the PackageInfo file cat > pkgbuild/flat/base.pkg/PackageInfo << EOF @@ -98,7 +99,7 @@ cat > pkgbuild/flat/Distribution << EOF Yggdrasil (${PKGNAME}-${PKGVERSION}) - +