diff --git a/CHANGELOG.md b/CHANGELOG.md index adc6335e..7a6dd187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.4.7] - 2022-11-20 + +### Added + +- Dropped outbound peerings will now try to reconnect after a single second, rather than waiting up to 60 seconds for the normal peer timer + +### Changed + +- Session encryption keys are now rotated at most once per minute, which reduces CPU usage and improves throughput on fast low latency links +- Buffers are now reused in the session encryption handler, which improves session throughput and reduces memory allocations +- Buffers are now reused in the router for DHT and path traffic, which improves overall routing throughput and reduces memory allocations + +### Fixed + +- A bug in the admin socket where requests fail unless `arguments` is specified has been fixed +- Certificates on TLS listeners will no longer expire after a year +- The `-address` and `-subnet` command line options now return a useful warning when no configuration is specified + ## [0.4.6] - 2022-10-25 ### Added diff --git a/cmd/genkeys/main.go b/cmd/genkeys/main.go index db807ec0..cceca273 100644 --- a/cmd/genkeys/main.go +++ b/cmd/genkeys/main.go @@ -17,9 +17,12 @@ import ( "encoding/hex" "fmt" "net" + "os" "runtime" - "github.com/RiV-chain/RiV-mesh/src/core" + "github.com/gologme/log" + + c "github.com/RiV-chain/RiV-mesh/src/core" ) type keySet struct { @@ -41,6 +44,8 @@ func main() { fmt.Println("-----") fmt.Println("Priv:", hex.EncodeToString(newKey.priv)) fmt.Println("Pub:", hex.EncodeToString(newKey.pub)) + logger := log.New(os.Stdout, "", log.Flags()) + core, _ := c.New(newKey.priv, logger, nil) addr := core.AddrForKey(newKey.pub) fmt.Println("IP:", net.IP(addr[:]).String()) } diff --git a/cmd/mesh/main.go b/cmd/mesh/main.go index 9073f708..49af5ea2 100644 --- a/cmd/mesh/main.go +++ b/cmd/mesh/main.go @@ -253,7 +253,12 @@ func run(args yggArgs, ctx context.Context) { return default: // No flags were provided, therefore print the list of flags to stdout. + fmt.Println("Usage:") flag.PrintDefaults() + + if args.getaddr || args.getsnet { + fmt.Println("\nError: You need to specify some config data using -useconf or -useconffile.") + } } // Have we got a working configuration? If we don't then it probably means // that neither -autoconf, -useconf or -useconffile were set above. Stop diff --git a/contrib/ansible/genkeys.go b/contrib/ansible/genkeys.go index 5d941ad1..8d752b50 100644 --- a/contrib/ansible/genkeys.go +++ b/contrib/ansible/genkeys.go @@ -13,8 +13,9 @@ import ( "net" "os" + c "github.com/RiV-chain/RiV-mesh/src/core" "github.com/cheggaaa/pb/v3" - "github.com/RiV-chain/RiV-mesh/src/address" + "github.com/gologme/log" ) var numHosts = flag.Int("hosts", 1, "number of host vars to generate") @@ -35,7 +36,6 @@ func main() { println("Can't generate less keys than hosts.") return } - var keys []keySet for i := 0; i < *numHosts+1; i++ { keys = append(keys, newKey()) @@ -77,7 +77,9 @@ func newKey() keySet { if err != nil { panic(err) } - ip := net.IP(address.AddrForKey(pub)[:]).String() + logger := log.New(os.Stdout, "", log.Flags()) + core, _ := c.New(priv, logger, nil) + ip := net.IP(core.AddrForKey(pub)[:]).String() return keySet{priv[:], pub[:], ip} } diff --git a/contrib/mobile/mobile.go b/contrib/mobile/mobile.go index 0c723833..a9f24e83 100644 --- a/contrib/mobile/mobile.go +++ b/contrib/mobile/mobile.go @@ -16,8 +16,6 @@ import ( "github.com/RiV-chain/RiV-mesh/src/ipv6rwc" "github.com/RiV-chain/RiV-mesh/src/multicast" "github.com/RiV-chain/RiV-mesh/src/version" - - _ "golang.org/x/mobile/bind" ) // RiV-mesh mobile package is meant to "plug the gap" for mobile support, as @@ -83,10 +81,10 @@ func (m *Mesh) StartJSON(configjson []byte) error { options := []multicast.SetupOption{} for _, intf := range m.config.MulticastInterfaces { options = append(options, multicast.MulticastInterface{ - Regex: regexp.MustCompile(intf.Regex), - Beacon: intf.Beacon, - Listen: intf.Listen, - Port: intf.Port, + Regex: regexp.MustCompile(intf.Regex), + Beacon: intf.Beacon, + Listen: intf.Listen, + Port: intf.Port, Priority: uint8(intf.Priority), }) } @@ -159,6 +157,11 @@ func (m *Mesh) Stop() error { return nil } +// Retry resets the peer connection timer and tries to dial them immediately. +func (m *Mesh) RetryPeersNow() { + m.core.RetryPeersNow() +} + // GenerateConfigJSON generates mobile-friendly configuration in JSON format func GenerateConfigJSON() []byte { nc := defaults.GenerateConfig() diff --git a/contrib/mobile/mobile_test.go b/contrib/mobile/mobile_test.go index 4111d6bf..d9024a65 100644 --- a/contrib/mobile/mobile_test.go +++ b/contrib/mobile/mobile_test.go @@ -3,7 +3,7 @@ package mobile import "testing" func TestStartYggdrasil(t *testing.T) { - ygg := &Mesh{} + mesh := &Mesh{} if err := mesh.StartAutoconfigure(); err != nil { t.Fatalf("Failed to start Mesh: %s", err) } diff --git a/go.mod b/go.mod index c24d027e..7ef69c22 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/RiV-chain/RiV-mesh go 1.17 require ( - github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2 + github.com/Arceliar/ironwood v0.0.0-20221115123222-ec61cea2f439 github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 github.com/cheggaaa/pb/v3 v3.0.8 github.com/gologme/log v1.2.0 diff --git a/go.sum b/go.sum index 70107bab..30f678f1 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,16 @@ -github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2 h1:Usab30pNT2i/vZvpXcN9uOr5IO1RZPcUqoGH0DIAPnU= -github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk= +github.com/Arceliar/ironwood v0.0.0-20221115123222-ec61cea2f439 h1:eOW6/XIs06TnUn9GPCnfv71CQZw8edP3u3mH3lZt6iM= +github.com/Arceliar/ironwood v0.0.0-20221115123222-ec61cea2f439/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= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -42,8 +43,6 @@ github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwM github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hjson/hjson-go v3.1.0+incompatible h1:DY/9yE8ey8Zv22bY+mHV1uk2yRy0h8tKhZ77hEdi0Aw= github.com/hjson/hjson-go v3.1.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio= -github.com/kardianos/minwinsvc v1.0.0 h1:+JfAi8IBJna0jY2dJGZqi7o15z13JelFIklJCAENALA= -github.com/kardianos/minwinsvc v1.0.0/go.mod h1:Bgd0oc+D0Qo3bBytmNtyRKVlp85dAloLKhfxanPFFRc= github.com/kardianos/minwinsvc v1.0.2 h1:JmZKFJQrmTGa/WiW+vkJXKmfzdjabuEW4Tirj5lLdR0= github.com/kardianos/minwinsvc v1.0.2/go.mod h1:LUZNYhNmxujx2tR7FbdxqYJ9XDDoCd3MQcl1o//FWl4= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -62,40 +61,26 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m 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/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= 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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/vikulin/sctp v0.0.0-20220918193719-c8cee09143f6 h1:j8DBhVyu5IOrjL8TKrodj8hrPhu1UcDLU39WInResBg= -github.com/vikulin/sctp v0.0.0-20220918193719-c8cee09143f6/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= -github.com/vikulin/sctp v0.0.0-20221007162951-ee34dc8ef4fb h1:BsQ30cGdJOu4vvpDcbGxV2lFHJI9wZ0/vEQ0tGkPwtY= -github.com/vikulin/sctp v0.0.0-20221007162951-ee34dc8ef4fb/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= -github.com/vikulin/sctp v0.0.0-20221007163900-14c90ba6cef7 h1:t8SpyJRWXFn2oFCOrx41xiHW5Paq0hI3MDvfNVXmSUg= -github.com/vikulin/sctp v0.0.0-20221007163900-14c90ba6cef7/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= -github.com/vikulin/sctp v0.0.0-20221007164225-10d5e6ecb1f3 h1:PjcompCCBrsiwQ6cl0bVNpBMVBsWO6u3ZGDRIsIA9is= -github.com/vikulin/sctp v0.0.0-20221007164225-10d5e6ecb1f3/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= -github.com/vikulin/sctp v0.0.0-20221007165105-a2fb1402929e h1:2L3RhOd9P1uAIH32fe2Yj1VhA5m9pwQxlfNcxxaDzGk= -github.com/vikulin/sctp v0.0.0-20221007165105-a2fb1402929e/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= -github.com/vikulin/sctp v0.0.0-20221009173008-ba8cb1782eb2 h1:TScABL/GNdjRpUD0aG8ppV7aOjWAh/jyLic9BUMVAmU= -github.com/vikulin/sctp v0.0.0-20221009173008-ba8cb1782eb2/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= -github.com/vikulin/sctp v0.0.0-20221009173321-b95fb2a7e8a8 h1:45QFbCDBaje6CtEVNzW3v961p9kg5OtkDqesrAXhr78= -github.com/vikulin/sctp v0.0.0-20221009173321-b95fb2a7e8a8/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= -github.com/vikulin/sctp v0.0.0-20221009175920-231a1a8f897c h1:ErkH7lmFcxa8fGsiJYZULCslf7vFCEtsmFeSSnMAyjU= -github.com/vikulin/sctp v0.0.0-20221009175920-231a1a8f897c/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= -github.com/vikulin/sctp v0.0.0-20221009183851-886ddb1d294f h1:wR6HtyVHroyQ/NcKA6xnRfqbOBlqMoEtL9qxcM/2BPc= -github.com/vikulin/sctp v0.0.0-20221009183851-886ddb1d294f/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/vikulin/sctp v0.0.0-20221009200520-ae0f2830e422 h1:KJn6ovcNlavPTgdK2uKJoonWPP3GTb8x4FyYPIrwpZw= github.com/vikulin/sctp v0.0.0-20221009200520-ae0f2830e422/go.mod h1:wbWp47D/qXkQrDuO8qSeUXdLN9qXNZzIgLGDQIoJlJU= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= @@ -110,35 +95,26 @@ github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= 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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -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/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e h1:zSgtO19fpg781xknwqiQPmOHaASr6E7ZVlTseLd9Fx4= -golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= -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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 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-20210726213435-c6fcb2dbf985/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= @@ -149,7 +125,6 @@ golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfS 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/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/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= @@ -163,7 +138,6 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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= @@ -183,12 +157,9 @@ golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -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.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 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= @@ -200,6 +171,9 @@ golang.zx2c4.com/wireguard/windows v0.4.12 h1:CUmbdWKVNzTSsVb4yUAiEwL3KsabdJkEPd golang.zx2c4.com/wireguard/windows v0.4.12/go.mod h1:PW4y+d9oY83XU9rRwRwrJDwEMuhVjMxu2gfD1cfzS7w= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/src/core/address_test.go b/src/core/address_test.go index f7673ca4..00bcc36c 100644 --- a/src/core/address_test.go +++ b/src/core/address_test.go @@ -7,83 +7,83 @@ import ( "testing" ) -func TestAddress_Address_IsValid(t *testing.T) { +func (c *Core) TestAddress_Address_IsValid(t *testing.T) { var address Address rand.Read(address[:]) address[0] = 0 - if address.IsValid() { + if c.IsValidAddress(address) { t.Fatal("invalid address marked as valid") } address[0] = 0xfd - if address.IsValid() { + if c.IsValidAddress(address) { t.Fatal("invalid address marked as valid") } address[0] = 0xfc - if !address.IsValid() { + if !c.IsValidAddress(address) { t.Fatal("valid address marked as invalid") } } -func TestAddress_Subnet_IsValid(t *testing.T) { +func (c *Core) TestAddress_Subnet_IsValid(t *testing.T) { var subnet Subnet rand.Read(subnet[:]) subnet[0] = 0 - if subnet.IsValid() { + if c.IsValidSubnet(subnet) { t.Fatal("invalid subnet marked as valid") } subnet[0] = 0xfc - if subnet.IsValid() { + if c.IsValidSubnet(subnet) { t.Fatal("invalid subnet marked as valid") } subnet[0] = 0xfd - if !subnet.IsValid() { + if !c.IsValidSubnet(subnet) { t.Fatal("valid subnet marked as invalid") } } -func TestAddress_AddrForKey(t *testing.T) { +func (c *Core) 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{ - f, c, 0, 132, 138, 96, 79, 187, 126, 67, 132, 101, 219, 141, 182, 104, 149, + 0xfc, 0, 132, 138, 96, 79, 187, 126, 67, 132, 101, 219, 141, 182, 104, 149, } - if *AddrForKey(publicKey) != expectedAddress { + if *c.AddrForKey(publicKey) != expectedAddress { t.Fatal("invalid address returned") } } -func TestAddress_SubnetForKey(t *testing.T) { +func (c *Core) 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{f, d, 0, 132, 138, 96, 79, 187, 126} + expectedSubnet := Subnet{0xfd, 0, 132, 138, 96, 79, 187, 126} - if *SubnetForKey(publicKey) != expectedSubnet { + if *c.SubnetForKey(publicKey) != expectedSubnet { t.Fatal("invalid subnet returned") } } -func TestAddress_Address_GetKey(t *testing.T) { +func (c *Core) TestAddress_Address_GetKey(t *testing.T) { address := Address{ - f, c, 0, 132, 138, 96, 79, 187, 126, 67, 132, 101, 219, 141, 182, 104, 149, + 0xfc, 0, 132, 138, 96, 79, 187, 126, 67, 132, 101, 219, 141, 182, 104, 149, } expectedPublicKey := ed25519.PublicKey{ @@ -93,13 +93,13 @@ func TestAddress_Address_GetKey(t *testing.T) { 255, 255, 255, 255, 255, 255, 255, 255, } - if !bytes.Equal(address.GetKey(), expectedPublicKey) { + if !bytes.Equal(c.GetAddressKey(address), expectedPublicKey) { t.Fatal("invalid public key returned") } } -func TestAddress_Subnet_GetKey(t *testing.T) { - subnet := Subnet{f, d, 0, 132, 138, 96, 79, 187, 126} +func (c *Core) TestAddress_Subnet_GetKey(t *testing.T) { + subnet := Subnet{0xfd, 0, 132, 138, 96, 79, 187, 126} expectedPublicKey := ed25519.PublicKey{ 189, 186, 207, 216, 34, 64, 255, 255, @@ -108,7 +108,7 @@ func TestAddress_Subnet_GetKey(t *testing.T) { 255, 255, 255, 255, 255, 255, 255, 255, } - if !bytes.Equal(subnet.GetKey(), expectedPublicKey) { + if !bytes.Equal(c.GetSubnetKey(subnet), expectedPublicKey) { t.Fatal("invalid public key returned") } } diff --git a/src/core/api.go b/src/core/api.go index f789af20..a26277d2 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -188,21 +188,25 @@ func (c *Core) SetLogger(log Logger) { // This adds the peer to the peer list, so that they will be called again if the // connection drops. -func (c *Core) AddPeer(peer string, intf string) error { - select { - case <-c.ctx.Done(): - return nil - default: +func (c *Core) AddPeer(uri string, sourceInterface string) error { + var known bool + phony.Block(c, func() { + _, known = c.config._peers[Peer{uri, sourceInterface}] + }) + if known { + return fmt.Errorf("peer already configured") } - u, err := url.Parse(peer) + u, err := url.Parse(uri) if err != nil { - c.log.Errorln("Failed to parse peer url:", peer, err) return err } - if err := c.CallPeer(u, intf); err != nil { - c.log.Errorln("Failed to add peer:", err) + info, err := c.links.call(u, sourceInterface, nil) + if err != nil { return err } + phony.Block(c, func() { + c.config._peers[Peer{uri, sourceInterface}] = &info + }) return nil } @@ -245,7 +249,7 @@ func (c *Core) RemovePeers() error { // This does not add the peer to the peer list, so if the connection drops, the // peer will not be called again automatically. func (c *Core) CallPeer(u *url.URL, sintf string) error { - _, err := c.links.call(u, sintf) + _, err := c.links.call(u, sintf, nil) return err } diff --git a/src/core/core.go b/src/core/core.go index bdbe8ee5..a150ee0f 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -20,7 +20,7 @@ import ( // The Core object represents the Mesh node. You should create a Core // object for each Mesh node you plan to run. type Core struct { - address Address + address Address // This is the main data structure that holds everything else for a node // 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 @@ -123,6 +123,13 @@ func (c *Core) _addPeerLoop() { }) } +func (c *Core) RetryPeersNow() { + if c.addPeerTimer != nil && !c.addPeerTimer.Stop() { + <-c.addPeerTimer.C + } + c.Act(nil, c._addPeerLoop) +} + // Stop shuts down the Mesh node. func (c *Core) Stop() { phony.Block(c, func() { diff --git a/src/core/link.go b/src/core/link.go index 8378b087..838897ea 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -22,64 +22,69 @@ import ( // linkInfo is used as a map key type linkInfo struct { - linkType string // Type of link, e.g. TCP, AWDL - local string // Local name or address - remote string // Remote name or address + linkType string // Type of link, e.g. TCP, AWDL + local string // Local name or address + remote string // Remote name or address +} + +type linkDial struct { + url *url.URL + sintf string } type link struct { - lname string - links *links - conn *linkConn - options linkOptions - info linkInfo - incoming bool - force bool + lname string + links *links + conn *linkConn + options linkOptions + info linkInfo + incoming bool + force bool } type linkOptions struct { - pinnedEd25519Keys map[keyArray]struct{} + pinnedEd25519Keys map[keyArray]struct{} priority uint8 } type Listener struct { - net.Listener - closed chan struct{} + net.Listener + closed chan struct{} } func (l *Listener) Close() error { - err := l.Listener.Close() - <-l.closed - return err + err := l.Listener.Close() + <-l.closed + return err } func (l *links) shutdown() { - phony.Block(l.tcp, func() { - for l := range l.tcp._listeners { - _ = l.Close() - } - }) - phony.Block(l.tls, func() { - for l := range l.tls._listeners { - _ = l.Close() - } - }) - phony.Block(l.unix, func() { - for l := range l.unix._listeners { - _ = l.Close() - } - }) + phony.Block(l.tcp, func() { + for l := range l.tcp._listeners { + _ = l.Close() + } + }) + phony.Block(l.tls, func() { + for l := range l.tls._listeners { + _ = l.Close() + } + }) + phony.Block(l.unix, func() { + for l := range l.unix._listeners { + _ = l.Close() + } + }) } func (l *links) isConnectedTo(info linkInfo) bool { - var isConnected bool - phony.Block(l, func() { - _, isConnected = l._links[info] - }) - return isConnected + var isConnected bool + phony.Block(l, func() { + _, isConnected = l._links[info] + }) + return isConnected } -func (l *links) create(conn net.Conn, name string, info linkInfo, incoming, force bool, options linkOptions) error { +func (l *links) create(conn net.Conn, dial *linkDial, name string, info linkInfo, incoming, force bool, options linkOptions) error { intf := link{ conn: &linkConn{ Conn: conn, @@ -93,14 +98,14 @@ func (l *links) create(conn net.Conn, name string, info linkInfo, incoming, forc force: force, } go func() { - if err := intf.handler(); err != nil { + if err := intf.handler(dial); err != nil { l.core.log.Errorf("Link handler %s error (%s): %s", name, conn.RemoteAddr(), err) } }() return nil } -func (intf *link) handler() error { +func (intf *link) handler(dial *linkDial) error { defer intf.conn.Close() // nolint:errcheck // Don't connect to this link more than once. @@ -203,6 +208,30 @@ func (intf *link) handler() error { intf.links.core.log.Infof("Disconnected %s %s: %s, source %s; error: %s", dir, strings.ToUpper(intf.info.linkType), remoteStr, localStr, err) } + + if !intf.incoming && dial != nil { + // The connection was one that we dialled, so wait a second and try to + // dial it again. + var retry func(attempt int) + retry = func(attempt int) { + // intf.links.core.log.Infof("Retrying %s (attempt %d of 5)...", dial.url.String(), attempt) + errch := make(chan error, 1) + if _, err := intf.links.call(dial.url, dial.sintf, errch); err != nil { + return + } + if err := <-errch; err != nil { + if attempt < 3 { + time.AfterFunc(time.Second, func() { + retry(attempt + 1) + }) + } + } + } + time.AfterFunc(time.Second, func() { + retry(1) + }) + } + return nil } diff --git a/src/core/link_linux.go b/src/core/link_linux.go index d712dfdb..63ad5d44 100644 --- a/src/core/link_linux.go +++ b/src/core/link_linux.go @@ -6,8 +6,8 @@ package core import ( "encoding/hex" "errors" - "io" "fmt" + "io" "net" "net/url" "strconv" @@ -51,9 +51,12 @@ func (l *links) init(c *Core) error { return nil } -func (l *links) call(u *url.URL, sintf string) (linkInfo, error) { - info := linkInfoFor(u.Scheme, sintf, u.Host) +func (l *links) call(u *url.URL, sintf string, errch chan<- error) (info linkInfo, err error) { + info = linkInfoFor(u.Scheme, sintf, u.Host) if l.isConnectedTo(info) { + if errch != nil { + close(errch) // already connected, no error + } return info, nil } options := linkOptions{ @@ -62,6 +65,9 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) { for _, pubkey := range u.Query()["key"] { sigPub, err := hex.DecodeString(pubkey) if err != nil { + if errch != nil { + close(errch) + } return info, fmt.Errorf("pinned key contains invalid hex characters") } var sigPubKey keyArray @@ -71,6 +77,9 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) { if p := u.Query().Get("priority"); p != "" { pi, err := strconv.ParseUint(p, 10, 8) if err != nil { + if errch != nil { + close(errch) + } return info, fmt.Errorf("priority invalid: %w", err) } options.priority = uint8(pi) @@ -78,15 +87,27 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) { switch info.linkType { case "tcp": go func() { + if errch != nil { + defer close(errch) + } if err := l.tcp.dial(u, options, sintf); err != nil && err != io.EOF { l.core.log.Warnf("Failed to dial TCP %s: %s\n", u.Host, err) + if errch != nil { + errch <- err + } } }() case "socks": go func() { + if errch != nil { + defer close(errch) + } if err := l.socks.dial(u, options); err != nil && err != io.EOF { l.core.log.Warnf("Failed to dial SOCKS %s: %s\n", u.Host, err) + if errch != nil { + errch <- err + } } }() @@ -109,30 +130,57 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) { } } go func() { + if errch != nil { + defer close(errch) + } if err := l.tls.dial(u, options, sintf, tlsSNI); err != nil && err != io.EOF { l.core.log.Warnf("Failed to dial TLS %s: %s\n", u.Host, err) + if errch != nil { + errch <- err + } } }() case "unix": go func() { + if errch != nil { + defer close(errch) + } if err := l.unix.dial(u, options, sintf); err != nil && err != io.EOF { l.core.log.Warnf("Failed to dial UNIX %s: %s\n", u.Host, err) + if errch != nil { + errch <- err + } } }() - case "sctp": - go func() { + case "sctp": + go func() { + if errch != nil { + defer close(errch) + } if err := l.sctp.dial(u, options, sintf); err != nil && err != io.EOF { - l.core.log.Warnf("Failed to dial SCTP %s: %s\n", u.Host, err) - } - }() + l.core.log.Warnf("Failed to dial SCTP %s: %s\n", u.Host, err) + if errch != nil { + errch <- err + } + } + }() case "mpath": go func() { + if errch != nil { + defer close(errch) + } if err := l.mpath.dial(u, options, sintf); err != nil && err != io.EOF { l.core.log.Warnf("Failed to dial MPATH %s: %s\n", u.Host, err) + if errch != nil { + errch <- err + } } }() default: + if errch != nil { + close(errch) + } return info, errors.New("unknown call scheme: " + u.Scheme) } return info, nil @@ -148,8 +196,8 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) { listener, err = l.tls.listen(u, sintf) case "unix": listener, err = l.unix.listen(u, sintf) - case "sctp": - listener, err = l.sctp.listen(u, sintf) + case "sctp": + listener, err = l.sctp.listen(u, sintf) case "mpath": listener, err = l.mpath.listen(u, sintf) default: diff --git a/src/core/link_mpath.go b/src/core/link_mpath.go index ea1b9291..3b394381 100644 --- a/src/core/link_mpath.go +++ b/src/core/link_mpath.go @@ -9,6 +9,7 @@ import ( "net" "net/url" "strings" + "github.com/getlantern/multipath" "github.com/Arceliar/phony" @@ -39,8 +40,12 @@ func (l *linkMPATH) dial(url *url.URL, options linkOptions, sintf string) error if err != nil { return err } - uri := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/") - return l.handler(uri, info, conn, options, false, false) + name := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/") + dial := &linkDial{ + url: url, + sintf: sintf, + } + return l.handler(dial, name, info, conn, options, false, false) } func (l *linkMPATH) listen(url *url.URL, sintf string) (*Listener, error) { @@ -74,10 +79,10 @@ func (l *linkMPATH) listen(url *url.URL, sintf string) (*Listener, error) { cancel() break } - addr := conn.RemoteAddr().(*net.TCPAddr) - name := fmt.Sprintf("mpath://%s", addr) - info := linkInfoFor("mpath", sintf, strings.SplitN(addr.IP.String(), "%", 2)[0]) - if err = l.handler(name, info, conn, linkOptions{}, true, addr.IP.IsLinkLocalUnicast()); err != nil { + raddr := conn.RemoteAddr().(*net.TCPAddr) + name := fmt.Sprintf("mpath://%s", raddr) + info := linkInfoFor("mpath", sintf, strings.SplitN(raddr.IP.String(), "%", 2)[0]) + if err = l.handler(nil, name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil { l.core.log.Errorln("Failed to create inbound link:", err) } } @@ -88,9 +93,10 @@ func (l *linkMPATH) listen(url *url.URL, sintf string) (*Listener, error) { return entry, nil } -func (l *linkMPATH) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error { +func (l *linkMPATH) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error { return l.links.create( conn, // connection + dial, // connection URL name, // connection name info, // connection info incoming, // not incoming @@ -146,7 +152,7 @@ func (l *linkMPATH) connFor(url *url.URL, sinterfaces string) (net.Conn, error) if sinterfaces != "" { sintfarray := strings.Split(sinterfaces, ",") for _, dst := range remoteTargets { - for _, sintf := range sintfarray { + for _, sintf := range sintfarray { ief, err := net.InterfaceByName(sintf) if err != nil { l.core.log.Errorln("interface %s not found", sintf) diff --git a/src/core/link_sctp_linux.go b/src/core/link_sctp_linux.go index 56087d27..d26743aa 100644 --- a/src/core/link_sctp_linux.go +++ b/src/core/link_sctp_linux.go @@ -5,12 +5,12 @@ package core import ( "context" + "encoding/json" "fmt" "net" "net/url" - "encoding/json" - "strings" "strconv" + "strings" "github.com/Arceliar/phony" sctp "github.com/vikulin/sctp" @@ -47,7 +47,7 @@ func (l *linkSCTP) dial(url *url.URL, options linkOptions, sintf string) error { if err != nil { return err } - raddress := l.getAddress(dst.String()+":"+port) + raddress := l.getAddress(dst.String() + ":" + port) var conn net.Conn laddress := l.getAddress("0.0.0.0:0") conn, err = sctp.NewSCTPConnection(laddress, laddress.AddressFamily, sctp.InitMsg{NumOstreams: 2, MaxInstreams: 2, MaxAttempts: 2, MaxInitTimeout: 5}, sctp.OneToOne, false) @@ -63,7 +63,11 @@ func (l *linkSCTP) dial(url *url.URL, options linkOptions, sintf string) error { //l.core.log.Printf("Read buffer %d", rbuf) //l.core.log.Printf("Write buffer %d", wbuf) conn.(*sctp.SCTPConn).SetEvents(sctp.SCTP_EVENT_DATA_IO) - return l.handler(url.String(), info, conn, options, false, false) + dial := &linkDial{ + url: url, + sintf: sintf, + } + return l.handler(dial, url.String(), info, conn, options, false, false) } func (l *linkSCTP) listen(url *url.URL, sintf string) (*Listener, error) { @@ -102,9 +106,9 @@ func (l *linkSCTP) listen(url *url.URL, sintf string) (*Listener, error) { } addr := conn.RemoteAddr().(*sctp.SCTPAddr) ips, err := json.Marshal(addr.IPAddrs) - if err != nil { - break - } + if err != nil { + break + } name := fmt.Sprintf("sctp://%s", ips) info := linkInfoFor("sctp", sintf, string(ips)) //conn.(*sctp.SCTPConn).SetWriteBuffer(324288) @@ -113,8 +117,8 @@ func (l *linkSCTP) listen(url *url.URL, sintf string) (*Listener, error) { rbuf, _ := conn.(*sctp.SCTPConn).GetReadBuffer() l.core.log.Printf("Read buffer %d", rbuf) - l.core.log.Printf("Write buffer %d", wbuf) - if err = l.handler(name, info, conn, linkOptions{}, true, addr.IPAddrs[0].IP.IsLinkLocalUnicast()); err != nil { + l.core.log.Printf("Write buffer %d", wbuf) + if err = l.handler(nil, name, info, conn, linkOptionsForListener(url), true, addr.IPAddrs[0].IP.IsLinkLocalUnicast()); err != nil { l.core.log.Errorln("Failed to create inbound link:", err) } } @@ -125,9 +129,10 @@ func (l *linkSCTP) listen(url *url.URL, sintf string) (*Listener, error) { return entry, nil } -func (l *linkSCTP) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool, force bool) error { +func (l *linkSCTP) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error { return l.links.create( conn, // connection + dial, // connection URL name, // connection name info, // connection info incoming, // not incoming @@ -161,7 +166,7 @@ func (l *linkSCTP) getAddress(host string) *sctp.SCTPAddr { } for _, i := range strings.Split(ip, ",") { if a, err := net.ResolveIPAddr("ip", i); err == nil { - fmt.Sprintf("Resolved address '%s' to %s", i, a) + l.core.log.Printf("Resolved address '%s' to %s", i, a) ips = append(ips, *a) } else { l.core.log.Errorln("Error resolving address '%s': %v", i, err) diff --git a/src/core/link_socks.go b/src/core/link_socks.go index 036de992..4cdffa51 100644 --- a/src/core/link_socks.go +++ b/src/core/link_socks.go @@ -37,16 +37,20 @@ func (l *linkSOCKS) dial(url *url.URL, options linkOptions) error { if err != nil { return err } - return l.handler(url.String(), info, conn, options, false) + dial := &linkDial{ + url: url, + } + return l.handler(dial, info, conn, options, false) } -func (l *linkSOCKS) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error { +func (l *linkSOCKS) handler(dial *linkDial, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error { return l.links.create( - conn, // connection - name, // connection name - info, // connection info - incoming, // not incoming - false, // not forced - options, // connection options + conn, // connection + dial, // connection URL + dial.url.String(), // connection name + info, // connection info + incoming, // not incoming + false, // not forced + options, // connection options ) } diff --git a/src/core/link_tcp.go b/src/core/link_tcp.go index 6f7cc34e..74f72e00 100644 --- a/src/core/link_tcp.go +++ b/src/core/link_tcp.go @@ -47,8 +47,12 @@ func (l *linkTCP) dial(url *url.URL, options linkOptions, sintf string) error { if err != nil { return err } - uri := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/") - return l.handler(uri, info, conn, options, false, false) + name := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/") + dial := &linkDial{ + url: url, + sintf: sintf, + } + return l.handler(dial, name, info, conn, options, false, false) } func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) { @@ -86,7 +90,7 @@ func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) { raddr := conn.RemoteAddr().(*net.TCPAddr) name := fmt.Sprintf("tcp://%s", raddr) info := linkInfoFor("tcp", sintf, tcpIDFor(laddr, raddr)) - if err = l.handler(name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil { + if err = l.handler(nil, name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil { l.core.log.Errorln("Failed to create inbound link:", err) } } @@ -97,9 +101,10 @@ func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) { return entry, nil } -func (l *linkTCP) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error { +func (l *linkTCP) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error { return l.links.create( conn, // connection + dial, // connection URL name, // connection name info, // connection info incoming, // not incoming diff --git a/src/core/link_tls.go b/src/core/link_tls.go index 4eeb8710..dda0e2fe 100644 --- a/src/core/link_tls.go +++ b/src/core/link_tls.go @@ -69,8 +69,12 @@ func (l *linkTLS) dial(url *url.URL, options linkOptions, sintf, sni string) err if err != nil { return err } - uri := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/") - return l.handler(uri, info, conn, options, false, false) + name := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/") + dial := &linkDial{ + url: url, + sintf: sintf, + } + return l.handler(dial, name, info, conn, options, false, false) } func (l *linkTLS) listen(url *url.URL, sintf string) (*Listener, error) { @@ -109,7 +113,7 @@ func (l *linkTLS) listen(url *url.URL, sintf string) (*Listener, error) { raddr := conn.RemoteAddr().(*net.TCPAddr) name := fmt.Sprintf("tls://%s", raddr) info := linkInfoFor("tls", sintf, tcpIDFor(laddr, raddr)) - if err = l.handler(name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil { + if err = l.handler(nil, name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil { l.core.log.Errorln("Failed to create inbound link:", err) } } @@ -120,20 +124,18 @@ func (l *linkTLS) listen(url *url.URL, sintf string) (*Listener, error) { return entry, nil } +// RFC5280 section 4.1.2.5 +var notAfterNeverExpires = time.Date(9999, time.December, 31, 23, 59, 59, 0, time.UTC) + func (l *linkTLS) generateConfig() (*tls.Config, error) { certBuf := &bytes.Buffer{} - - // TODO: because NotAfter is finite, we should add some mechanism to - // regenerate the certificate and restart the listeners periodically - // for nodes with very high uptimes. Perhaps regenerate certs and restart - // listeners every few months or so. cert := x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: hex.EncodeToString(l.links.core.public[:]), }, NotBefore: time.Now(), - NotAfter: time.Now().Add(time.Hour * 24 * 365), + NotAfter: notAfterNeverExpires, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, @@ -167,6 +169,6 @@ func (l *linkTLS) generateConfig() (*tls.Config, error) { }, nil } -func (l *linkTLS) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error { - return l.tcp.handler(name, info, conn, options, incoming, force) +func (l *linkTLS) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error { + return l.tcp.handler(dial, name, info, conn, options, incoming, force) } diff --git a/src/core/link_unix.go b/src/core/link_unix.go index 50183a25..7f782575 100644 --- a/src/core/link_unix.go +++ b/src/core/link_unix.go @@ -45,7 +45,10 @@ func (l *linkUNIX) dial(url *url.URL, options linkOptions, _ string) error { if err != nil { return err } - return l.handler(url.String(), info, conn, options, false) + dial := &linkDial{ + url: url, + } + return l.handler(dial, url.String(), info, conn, options, false) } func (l *linkUNIX) listen(url *url.URL, _ string) (*Listener, error) { @@ -74,7 +77,7 @@ func (l *linkUNIX) listen(url *url.URL, _ string) (*Listener, error) { break } info := linkInfoFor("unix", "", url.String()) - if err = l.handler(url.String(), info, conn, linkOptionsForListener(url), true); err != nil { + if err = l.handler(nil, url.String(), info, conn, linkOptionsForListener(url), true); err != nil { l.core.log.Errorln("Failed to create inbound link:", err) } } @@ -85,9 +88,10 @@ func (l *linkUNIX) listen(url *url.URL, _ string) (*Listener, error) { return entry, nil } -func (l *linkUNIX) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error { +func (l *linkUNIX) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error { return l.links.create( conn, // connection + dial, // connection URL name, // connection name info, // connection info incoming, // not incoming diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 427666fa..495eb59e 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -30,6 +30,7 @@ type Multicast struct { _isOpen bool _listeners map[string]*listenerInfo _interfaces map[string]*interfaceInfo + _timer *time.Timer config struct { _groupAddr GroupAddress _interfaces map[MulticastInterface]struct{} @@ -206,6 +207,15 @@ func (m *Multicast) _getAllowedInterfaces() map[string]*interfaceInfo { return interfaces } +func (m *Multicast) AnnounceNow() { + phony.Block(m, func() { + if m._timer != nil && !m._timer.Stop() { + <-m._timer.C + } + m.Act(nil, m._announce) + }) +} + func (m *Multicast) _announce() { if !m._isOpen { return @@ -328,7 +338,7 @@ func (m *Multicast) _announce() { break } } - time.AfterFunc(time.Second, func() { + m._timer = time.AfterFunc(time.Second, func() { m.Act(nil, m._announce) }) }