From 2c1323ece60443015e969f056ebf19e058cf4e54 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 17 May 2016 00:05:38 +0000 Subject: [PATCH] lib/connections: Un-deprecate relaysEnabled (fixes #3074) GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3098 --- .../syncthing/settings/settingsModalView.html | 23 ++- lib/config/config.go | 64 ++++--- lib/config/config_test.go | 62 +++++++ lib/config/optionsconfiguration.go | 12 +- lib/connections/relay_dial.go | 12 +- lib/connections/relay_listen.go | 34 ++-- lib/connections/service.go | 161 ++++++++++++------ lib/connections/structs.go | 10 +- lib/connections/tcp_dial.go | 19 ++- lib/connections/tcp_listen.go | 63 ++++++- lib/model/model.go | 1 + lib/relay/client/static.go | 3 +- test/h1/config.xml | 35 ++-- 13 files changed, 371 insertions(+), 128 deletions(-) diff --git a/gui/default/syncthing/settings/settingsModalView.html b/gui/default/syncthing/settings/settingsModalView.html index be66bc4ef..44c74a7a3 100644 --- a/gui/default/syncthing/settings/settingsModalView.html +++ b/gui/default/syncthing/settings/settingsModalView.html @@ -56,11 +56,24 @@ -
-
- +
+
+
+
+ +
+
+
+
+
+
+ +
+
diff --git a/lib/config/config.go b/lib/config/config.go index 97809f4b6..dd04c15e2 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -29,9 +29,9 @@ const ( var ( // DefaultListenAddresses should be substituted when the configuration - // contains default. This is - // done by the "consumer" of the configuration, as we don't want these - // saved to the config. + // contains default. This is done by the + // "consumer" of the configuration as we don't want these saved to the + // config. DefaultListenAddresses = []string{ "tcp://0.0.0.0:22000", "dynamic+https://relays.syncthing.net/endpoint", @@ -258,27 +258,53 @@ func convertV13V14(cfg *Configuration) { // Not using the ignore cache is the new default. Disable it on existing // configurations. cfg.Options.CacheIgnoredFiles = false - cfg.Options.NATEnabled = cfg.Options.DeprecatedUPnPEnabled - cfg.Options.NATLeaseM = cfg.Options.DeprecatedUPnPLeaseM - cfg.Options.NATRenewalM = cfg.Options.DeprecatedUPnPRenewalM - cfg.Options.NATTimeoutS = cfg.Options.DeprecatedUPnPTimeoutS - if cfg.Options.DeprecatedRelaysEnabled { - cfg.Options.ListenAddresses = append(cfg.Options.ListenAddresses, cfg.Options.DeprecatedRelayServers...) - // Replace our two fairly long addresses with 'default' if both exist. - var newAddresses []string - for _, addr := range cfg.Options.ListenAddresses { - if addr != "tcp://0.0.0.0:22000" && addr != "dynamic+https://relays.syncthing.net/endpoint" { - newAddresses = append(newAddresses, addr) - } - } - if len(newAddresses)+2 == len(cfg.Options.ListenAddresses) { - cfg.Options.ListenAddresses = append([]string{"default"}, newAddresses...) + // Migrate UPnP -> NAT options + cfg.Options.NATEnabled = cfg.Options.DeprecatedUPnPEnabled + cfg.Options.DeprecatedUPnPEnabled = false + cfg.Options.NATLeaseM = cfg.Options.DeprecatedUPnPLeaseM + cfg.Options.DeprecatedUPnPLeaseM = 0 + cfg.Options.NATRenewalM = cfg.Options.DeprecatedUPnPRenewalM + cfg.Options.DeprecatedUPnPRenewalM = 0 + cfg.Options.NATTimeoutS = cfg.Options.DeprecatedUPnPTimeoutS + cfg.Options.DeprecatedUPnPTimeoutS = 0 + + // Replace the default listen address "tcp://0.0.0.0:22000" with the + // string "default", but only if we also have the default relay pool + // among the relay servers as this is implied by the new "default" + // entry. + hasDefault := false + for _, raddr := range cfg.Options.DeprecatedRelayServers { + if raddr == "dynamic+https://relays.syncthing.net/endpoint" { + for i, addr := range cfg.Options.ListenAddresses { + if addr == "tcp://0.0.0.0:22000" { + cfg.Options.ListenAddresses[i] = "default" + hasDefault = true + break + } + } + break } } - cfg.Options.DeprecatedRelaysEnabled = false + + // Copy relay addresses into listen addresses. + for _, addr := range cfg.Options.DeprecatedRelayServers { + if hasDefault && addr == "dynamic+https://relays.syncthing.net/endpoint" { + // Skip the default relay address if we already have the + // "default" entry in the list. + continue + } + if addr == "" { + continue + } + cfg.Options.ListenAddresses = append(cfg.Options.ListenAddresses, addr) + } + cfg.Options.DeprecatedRelayServers = nil + // For consistency + sort.Strings(cfg.Options.ListenAddresses) + var newAddrs []string for _, addr := range cfg.Options.GlobalAnnServers { if addr != "default" { diff --git a/lib/config/config_test.go b/lib/config/config_test.go index 2b4a1fe13..38c175b55 100644 --- a/lib/config/config_test.go +++ b/lib/config/config_test.go @@ -12,7 +12,9 @@ import ( "fmt" "os" "path/filepath" + "reflect" "runtime" + "sort" "strings" "testing" @@ -40,6 +42,7 @@ func TestDefaultValues(t *testing.T) { MaxSendKbps: 0, MaxRecvKbps: 0, ReconnectIntervalS: 60, + RelaysEnabled: true, RelayReconnectIntervalM: 10, StartBrowser: true, NATEnabled: true, @@ -169,6 +172,7 @@ func TestOverriddenValues(t *testing.T) { MaxSendKbps: 1234, MaxRecvKbps: 2341, ReconnectIntervalS: 6000, + RelaysEnabled: false, RelayReconnectIntervalM: 20, StartBrowser: false, NATEnabled: false, @@ -616,3 +620,61 @@ func TestRemoveDuplicateDevicesFolders(t *testing.T) { t.Errorf("Incorrect number of folder devices, %d != 2", l) } } + +func TestV14ListenAddressesMigration(t *testing.T) { + tcs := [][3][]string{ + + // Default listen plus default relays is now "default" + { + {"tcp://0.0.0.0:22000"}, + {"dynamic+https://relays.syncthing.net/endpoint"}, + {"default"}, + }, + // Default listen address without any relay addresses gets converted + // to just the listen address. It's easier this way, and frankly the + // user has gone to some trouble to get the empty string in the + // config to start with... + { + {"tcp://0.0.0.0:22000"}, // old listen addrs + {""}, // old relay addrs + {"tcp://0.0.0.0:22000"}, // new listen addrs + }, + // Default listen plus non-default relays gets copied verbatim + { + {"tcp://0.0.0.0:22000"}, + {"dynamic+https://other.example.com"}, + {"tcp://0.0.0.0:22000", "dynamic+https://other.example.com"}, + }, + // Non-default listen plus default relays gets copied verbatim + { + {"tcp://1.2.3.4:22000"}, + {"dynamic+https://relays.syncthing.net/endpoint"}, + {"tcp://1.2.3.4:22000", "dynamic+https://relays.syncthing.net/endpoint"}, + }, + // Default stuff gets sucked into "default", the rest gets copied + { + {"tcp://0.0.0.0:22000", "tcp://1.2.3.4:22000"}, + {"dynamic+https://relays.syncthing.net/endpoint", "relay://other.example.com"}, + {"default", "tcp://1.2.3.4:22000", "relay://other.example.com"}, + }, + } + + for _, tc := range tcs { + cfg := Configuration{ + Version: 13, + Options: OptionsConfiguration{ + ListenAddresses: tc[0], + DeprecatedRelayServers: tc[1], + }, + } + convertV13V14(&cfg) + if cfg.Version != 14 { + t.Error("Configuration was not converted") + } + + sort.Strings(tc[2]) + if !reflect.DeepEqual(cfg.Options.ListenAddresses, tc[2]) { + t.Errorf("Migration error; actual %#v != expected %#v", cfg.Options.ListenAddresses, tc[2]) + } + } +} diff --git a/lib/config/optionsconfiguration.go b/lib/config/optionsconfiguration.go index ed7aecec3..0781438e5 100644 --- a/lib/config/optionsconfiguration.go +++ b/lib/config/optionsconfiguration.go @@ -16,6 +16,7 @@ type OptionsConfiguration struct { MaxSendKbps int `xml:"maxSendKbps" json:"maxSendKbps"` MaxRecvKbps int `xml:"maxRecvKbps" json:"maxRecvKbps"` ReconnectIntervalS int `xml:"reconnectionIntervalS" json:"reconnectionIntervalS" default:"60"` + RelaysEnabled bool `xml:"relaysEnabled" json:"relaysEnabled" default:"true"` RelayReconnectIntervalM int `xml:"relayReconnectIntervalM" json:"relayReconnectIntervalM" default:"10"` StartBrowser bool `xml:"startBrowser" json:"startBrowser" default:"true"` NATEnabled bool `xml:"natEnabled" json:"natEnabled" default:"true"` @@ -40,12 +41,11 @@ type OptionsConfiguration struct { OverwriteRemoteDevNames bool `xml:"overwriteRemoteDeviceNamesOnConnect" json:"overwriteRemoteDeviceNamesOnConnect" default:"false"` TempIndexMinBlocks int `xml:"tempIndexMinBlocks" json:"tempIndexMinBlocks" default:"10"` - DeprecatedUPnPEnabled bool `xml:"upnpEnabled" json:"-"` - DeprecatedUPnPLeaseM int `xml:"upnpLeaseMinutes" json:"-"` - DeprecatedUPnPRenewalM int `xml:"upnpRenewalMinutes" json:"-"` - DeprecatedUPnPTimeoutS int `xml:"upnpTimeoutSeconds" json:"-"` - DeprecatedRelaysEnabled bool `xml:"relaysEnabled" json:"-"` - DeprecatedRelayServers []string `xml:"relayServer" json:"-"` + DeprecatedUPnPEnabled bool `xml:"upnpEnabled,omitempty" json:"-"` + DeprecatedUPnPLeaseM int `xml:"upnpLeaseMinutes,omitempty" json:"-"` + DeprecatedUPnPRenewalM int `xml:"upnpRenewalMinutes,omitempty" json:"-"` + DeprecatedUPnPTimeoutS int `xml:"upnpTimeoutSeconds,omitempty" json:"-"` + DeprecatedRelayServers []string `xml:"relayServer,omitempty" json:"-"` } func (orig OptionsConfiguration) Copy() OptionsConfiguration { diff --git a/lib/connections/relay_dial.go b/lib/connections/relay_dial.go index d859859fb..d18625ae8 100644 --- a/lib/connections/relay_dial.go +++ b/lib/connections/relay_dial.go @@ -70,10 +70,6 @@ func (d *relayDialer) RedialFrequency() time.Duration { return time.Duration(d.cfg.Options().RelayReconnectIntervalM) * time.Minute } -func (d *relayDialer) String() string { - return "Relay Dialer" -} - type relayDialerFactory struct{} func (relayDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDialer { @@ -86,3 +82,11 @@ func (relayDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDi func (relayDialerFactory) Priority() int { return relayPriority } + +func (relayDialerFactory) Enabled(cfg config.Configuration) bool { + return cfg.Options.RelaysEnabled +} + +func (relayDialerFactory) String() string { + return "Relay Dialer" +} diff --git a/lib/connections/relay_listen.go b/lib/connections/relay_listen.go index 2c3dddfde..68f8b62e7 100644 --- a/lib/connections/relay_listen.go +++ b/lib/connections/relay_listen.go @@ -13,23 +13,26 @@ import ( "sync" "time" + "github.com/syncthing/syncthing/lib/config" "github.com/syncthing/syncthing/lib/dialer" "github.com/syncthing/syncthing/lib/nat" "github.com/syncthing/syncthing/lib/relay/client" ) func init() { - listeners["relay"] = newRelayListener - listeners["dynamic+http"] = newRelayListener - listeners["dynamic+https"] = newRelayListener + factory := &relayListenerFactory{} + listeners["relay"] = factory + listeners["dynamic+http"] = factory + listeners["dynamic+https"] = factory } type relayListener struct { onAddressesChangedNotifier - uri *url.URL - tlsCfg *tls.Config - conns chan IntermediateConnection + uri *url.URL + tlsCfg *tls.Config + conns chan IntermediateConnection + factory listenerFactory err error client client.RelayClient @@ -154,14 +157,25 @@ func (t *relayListener) Error() error { return cerr } +func (t *relayListener) Factory() listenerFactory { + return t.factory +} + func (t *relayListener) String() string { return t.uri.String() } -func newRelayListener(uri *url.URL, tlsCfg *tls.Config, conns chan IntermediateConnection, natService *nat.Service) genericListener { +type relayListenerFactory struct{} + +func (f *relayListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.Config, conns chan IntermediateConnection, natService *nat.Service) genericListener { return &relayListener{ - uri: uri, - tlsCfg: tlsCfg, - conns: conns, + uri: uri, + tlsCfg: tlsCfg, + conns: conns, + factory: f, } } + +func (relayListenerFactory) Enabled(cfg config.Configuration) bool { + return cfg.Options.RelaysEnabled +} diff --git a/lib/connections/service.go b/lib/connections/service.go index 857b44803..5c80abbbc 100644 --- a/lib/connections/service.go +++ b/lib/connections/service.go @@ -9,6 +9,7 @@ package connections import ( "crypto/tls" "encoding/binary" + "errors" "fmt" "io" "net" @@ -112,6 +113,10 @@ func NewService(cfg *config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg * return service } +var ( + errDisabled = errors.New("disabled by configuration") +) + func (s *Service) handle() { next: for c := range s.conns { @@ -237,24 +242,35 @@ next: func (s *Service) connect() { nextDial := make(map[string]time.Time) - delay := time.Second - sleep := time.Second - bestDialerPrio := 1<<31 - 1 // worse prio won't build on 32 bit - for _, df := range dialers { - if prio := df.Priority(); prio < bestDialerPrio { - bestDialerPrio = prio - } - } + // Used as delay for the first few connection attempts, increases + // exponentially + initialRampup := time.Second + + // Calculated from actual dialers reconnectInterval + var sleep time.Duration for { + cfg := s.cfg.Raw() + + bestDialerPrio := 1<<31 - 1 // worse prio won't build on 32 bit + for _, df := range dialers { + if !df.Enabled(cfg) { + continue + } + if prio := df.Priority(); prio < bestDialerPrio { + bestDialerPrio = prio + } + } + l.Debugln("Reconnect loop") now := time.Now() var seen []string nextDevice: - for deviceID, deviceCfg := range s.cfg.Devices() { + for _, deviceCfg := range cfg.Devices { + deviceID := deviceCfg.DeviceID if deviceID == s.myID { continue } @@ -292,35 +308,40 @@ func (s *Service) connect() { seen = append(seen, addrs...) for _, addr := range addrs { + nextDialAt, ok := nextDial[addr] + if ok && initialRampup >= sleep && nextDialAt.After(now) { + l.Debugf("Not dialing %v as sleep is %v, next dial is at %s and current time is %s", addr, sleep, nextDialAt, now) + continue + } + // If we fail at any step before actually getting the dialer + // retry in a minute + nextDial[addr] = now.Add(time.Minute) + uri, err := url.Parse(addr) if err != nil { - l.Infoln("Failed to parse connection url:", addr, err) + l.Infof("Dialer for %s: %v", addr, err) continue } - dialerFactory, ok := dialers[uri.Scheme] - if !ok { - l.Debugln("Unknown address schema", uri) + dialerFactory, err := s.getDialerFactory(cfg, uri) + if err == errDisabled { + l.Debugln("Dialer for", uri, "is disabled") + continue + } + if err != nil { + l.Infof("Dialer for %v: %v", uri, err) + continue + } + + if connected && dialerFactory.Priority() >= ct.Priority { + l.Debugf("Not dialing using %s as priorty is less than current connection (%d >= %d)", dialerFactory, dialerFactory.Priority(), ct.Priority) continue } dialer := dialerFactory.New(s.cfg, s.tlsCfg) - - nextDialAt, ok := nextDial[uri.String()] - // See below for comments on this delay >= sleep check - if delay >= sleep && ok && nextDialAt.After(now) { - l.Debugf("Not dialing as next dial is at %s and current time is %s", nextDialAt, now) - continue - } - - nextDial[uri.String()] = now.Add(dialer.RedialFrequency()) - - if connected && dialer.Priority() >= ct.Priority { - l.Debugf("Not dialing using %s as priorty is less than current connection (%d >= %d)", dialer, dialer.Priority(), ct.Priority) - continue - } - l.Debugln("dial", deviceCfg.DeviceID, uri) + nextDial[addr] = now.Add(dialer.RedialFrequency()) + conn, err := dialer.Dial(deviceID, uri) if err != nil { l.Debugln("dial failed", deviceCfg.DeviceID, uri, err) @@ -338,12 +359,12 @@ func (s *Service) connect() { nextDial, sleep = filterAndFindSleepDuration(nextDial, seen, now) - // delay variable is used to trigger much more frequent dialing after - // initial startup, essentially causing redials every 1, 2, 4, 8... seconds - if delay < sleep { - time.Sleep(delay) - delay *= 2 + if initialRampup < sleep { + l.Debugln("initial rampup; sleep", initialRampup, "and update to", initialRampup*2) + time.Sleep(initialRampup) + initialRampup *= 2 } else { + l.Debugln("sleep until next dial", sleep) time.Sleep(sleep) } } @@ -366,24 +387,16 @@ func (s *Service) shouldLimit(addr net.Addr) bool { return !tcpaddr.IP.IsLoopback() } -func (s *Service) createListener(addr string) { +func (s *Service) createListener(factory listenerFactory, uri *url.URL) bool { // must be called with listenerMut held - uri, err := url.Parse(addr) - if err != nil { - l.Infoln("Failed to parse listen address:", addr, err) - return - } - listenerFactory, ok := listeners[uri.Scheme] - if !ok { - l.Infoln("Unknown listen address scheme:", uri.String()) - return - } + l.Debugln("Starting listener", uri) - listener := listenerFactory(uri, s.tlsCfg, s.conns, s.natService) + listener := factory.New(uri, s.cfg, s.tlsCfg, s.conns, s.natService) listener.OnAddressesChanged(s.logListenAddressesChangedEvent) - s.listeners[addr] = listener - s.listenerTokens[addr] = s.Add(listener) + s.listeners[uri.String()] = listener + s.listenerTokens[uri.String()] = s.Add(listener) + return true } func (s *Service) logListenAddressesChangedEvent(l genericListener) { @@ -417,15 +430,33 @@ func (s *Service) CommitConfiguration(from, to config.Configuration) bool { s.listenersMut.Lock() seen := make(map[string]struct{}) for _, addr := range config.Wrap("", to).ListenAddresses() { - if _, ok := s.listeners[addr]; !ok { - l.Debugln("Staring listener", addr) - s.createListener(addr) + if _, ok := s.listeners[addr]; ok { + seen[addr] = struct{}{} + continue } + + uri, err := url.Parse(addr) + if err != nil { + l.Infof("Listener for %s: %v", addr, err) + continue + } + + factory, err := s.getListenerFactory(to, uri) + if err == errDisabled { + l.Debugln("Listener for", uri, "is disabled") + continue + } + if err != nil { + l.Infof("Listener for %v: %v", uri, err) + continue + } + + s.createListener(factory, uri) seen[addr] = struct{}{} } - for addr := range s.listeners { - if _, ok := seen[addr]; !ok { + for addr, listener := range s.listeners { + if _, ok := seen[addr]; !ok || !listener.Factory().Enabled(to) { l.Debugln("Stopping listener", addr) s.Remove(s.listenerTokens[addr]) delete(s.listenerTokens, addr) @@ -494,6 +525,32 @@ func (s *Service) Status() map[string]interface{} { return result } +func (s *Service) getDialerFactory(cfg config.Configuration, uri *url.URL) (dialerFactory, error) { + dialerFactory, ok := dialers[uri.Scheme] + if !ok { + return nil, fmt.Errorf("unknown address scheme %q", uri.Scheme) + } + + if !dialerFactory.Enabled(cfg) { + return nil, errDisabled + } + + return dialerFactory, nil +} + +func (s *Service) getListenerFactory(cfg config.Configuration, uri *url.URL) (listenerFactory, error) { + listenerFactory, ok := listeners[uri.Scheme] + if !ok { + return nil, fmt.Errorf("unknown address scheme %q", uri.Scheme) + } + + if !listenerFactory.Enabled(cfg) { + return nil, errDisabled + } + + return listenerFactory, nil +} + func exchangeHello(c net.Conn, h protocol.HelloMessage) (protocol.HelloMessage, error) { if err := c.SetDeadline(time.Now().Add(2 * time.Second)); err != nil { return protocol.HelloMessage{}, err diff --git a/lib/connections/structs.go b/lib/connections/structs.go index 73fb9e124..33ce38020 100644 --- a/lib/connections/structs.go +++ b/lib/connections/structs.go @@ -31,16 +31,19 @@ type Connection struct { type dialerFactory interface { New(*config.Wrapper, *tls.Config) genericDialer Priority() int + Enabled(config.Configuration) bool + String() string } type genericDialer interface { Dial(protocol.DeviceID, *url.URL) (IntermediateConnection, error) - Priority() int RedialFrequency() time.Duration - String() string } -type listenerFactory func(*url.URL, *tls.Config, chan IntermediateConnection, *nat.Service) genericListener +type listenerFactory interface { + New(*url.URL, *config.Wrapper, *tls.Config, chan IntermediateConnection, *nat.Service) genericListener + Enabled(config.Configuration) bool +} type genericListener interface { Serve() @@ -58,6 +61,7 @@ type genericListener interface { Error() error OnAddressesChanged(func(genericListener)) String() string + Factory() listenerFactory } type Model interface { diff --git a/lib/connections/tcp_dial.go b/lib/connections/tcp_dial.go index 2d111dda0..c409680fa 100644 --- a/lib/connections/tcp_dial.go +++ b/lib/connections/tcp_dial.go @@ -20,8 +20,9 @@ import ( const tcpPriority = 10 func init() { + factory := &tcpDialerFactory{} for _, scheme := range []string{"tcp", "tcp4", "tcp6"} { - dialers[scheme] = tcpDialerFactory{} + dialers[scheme] = factory } } @@ -55,18 +56,10 @@ func (d *tcpDialer) Dial(id protocol.DeviceID, uri *url.URL) (IntermediateConnec return IntermediateConnection{tc, "TCP (Client)", tcpPriority}, nil } -func (tcpDialer) Priority() int { - return tcpPriority -} - func (d *tcpDialer) RedialFrequency() time.Duration { return time.Duration(d.cfg.Options().ReconnectIntervalS) * time.Second } -func (d *tcpDialer) String() string { - return "TCP Dialer" -} - type tcpDialerFactory struct{} func (tcpDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDialer { @@ -79,3 +72,11 @@ func (tcpDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDial func (tcpDialerFactory) Priority() int { return tcpPriority } + +func (tcpDialerFactory) Enabled(cfg config.Configuration) bool { + return true +} + +func (tcpDialerFactory) String() string { + return "TCP Dialer" +} diff --git a/lib/connections/tcp_listen.go b/lib/connections/tcp_listen.go index 66bc945ad..0b56cae36 100644 --- a/lib/connections/tcp_listen.go +++ b/lib/connections/tcp_listen.go @@ -14,23 +14,26 @@ import ( "sync" "time" + "github.com/syncthing/syncthing/lib/config" "github.com/syncthing/syncthing/lib/dialer" "github.com/syncthing/syncthing/lib/nat" ) func init() { + factory := &tcpListenerFactory{} for _, scheme := range []string{"tcp", "tcp4", "tcp6"} { - listeners[scheme] = newTCPListener + listeners[scheme] = factory } } type tcpListener struct { onAddressesChangedNotifier - uri *url.URL - tlsCfg *tls.Config - stop chan struct{} - conns chan IntermediateConnection + uri *url.URL + tlsCfg *tls.Config + stop chan struct{} + conns chan IntermediateConnection + factory listenerFactory natService *nat.Service mapping *nat.Mapping @@ -63,6 +66,9 @@ func (t *tcpListener) Serve() { } defer listener.Close() + l.Infof("TCP listener (%v) starting", listener.Addr()) + defer l.Infof("TCP listener (%v) shutting down", listener.Addr()) + mapping := t.natService.NewMapping(nat.TCP, tcaddr.IP, tcaddr.Port) mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) { t.notifyAddressesChanged(t) @@ -152,16 +158,61 @@ func (t *tcpListener) String() string { return t.uri.String() } -func newTCPListener(uri *url.URL, tlsCfg *tls.Config, conns chan IntermediateConnection, natService *nat.Service) genericListener { +func (t *tcpListener) Factory() listenerFactory { + return t.factory +} + +type tcpListenerFactory struct{} + +func (f *tcpListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.Config, conns chan IntermediateConnection, natService *nat.Service) genericListener { return &tcpListener{ uri: fixupPort(uri), tlsCfg: tlsCfg, conns: conns, natService: natService, stop: make(chan struct{}), + factory: f, } } +func (tcpListenerFactory) Enabled(cfg config.Configuration) bool { + return true +} + +func isPublicIPv4(ip net.IP) bool { + ip = ip.To4() + if ip == nil { + // Not an IPv4 address (IPv6) + return false + } + + // IsGlobalUnicast below only checks that it's not link local or + // multicast, and we want to exclude private (NAT:ed) addresses as well. + rfc1918 := []net.IPNet{ + {IP: net.IP{10, 0, 0, 0}, Mask: net.IPMask{255, 0, 0, 0}}, + {IP: net.IP{172, 16, 0, 0}, Mask: net.IPMask{255, 240, 0, 0}}, + {IP: net.IP{192, 168, 0, 0}, Mask: net.IPMask{255, 255, 0, 0}}, + } + for _, n := range rfc1918 { + if n.Contains(ip) { + return false + } + } + + return ip.IsGlobalUnicast() +} + +func isPublicIPv6(ip net.IP) bool { + if ip.To4() != nil { + // Not an IPv6 address (IPv4) + // (To16() returns a v6 mapped v4 address so can't be used to check + // that it's an actual v6 address) + return false + } + + return ip.IsGlobalUnicast() +} + func fixupPort(uri *url.URL) *url.URL { copyURI := *uri diff --git a/lib/model/model.go b/lib/model/model.go index 5c3cae654..057ee36ba 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -2018,6 +2018,7 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool { from.Options.URAccepted = to.Options.URAccepted from.Options.URUniqueID = to.Options.URUniqueID from.Options.ListenAddresses = to.Options.ListenAddresses + from.Options.RelaysEnabled = to.Options.RelaysEnabled // All of the other generic options require restart. Or at least they may; // removing this check requires going through those options carefully and // making sure there are individual services that handle them correctly. diff --git a/lib/relay/client/static.go b/lib/relay/client/static.go index c3a83608c..d9487bc2b 100644 --- a/lib/relay/client/static.go +++ b/lib/relay/client/static.go @@ -89,7 +89,8 @@ func (c *staticClient) Serve() { return } - l.Infoln("Joined relay", c.uri) + l.Infof("Joined relay %s://%s", c.uri.Scheme, c.uri.Host) + defer l.Infof("Disconnected from relay %s://%s", c.uri.Scheme, c.uri.Host) c.mut.Lock() c.connected = true diff --git a/test/h1/config.xml b/test/h1/config.xml index ee9e510df..7152f6be3 100644 --- a/test/h1/config.xml +++ b/test/h1/config.xml @@ -1,5 +1,5 @@ - - + + @@ -15,8 +15,10 @@ 0 0 -1 + false + false - + 1 @@ -30,6 +32,8 @@ 0 0 -1 + false + false
tcp://127.0.0.1:22004
@@ -51,26 +55,25 @@ testuser $2a$10$7tKL5uvLDGn5s2VLPM2yWOK/II45az0mTel8hxAUJDRQN1Tk2QYwu abc123 + default tcp://127.0.0.1:22001 + dynamic+https://relays.syncthing.net/endpoint default false true 21027 [ff12::8384]:21027 - dynamic+https://relays.syncthing.net/endpoint 0 0 5 - true 10 - false false - true - 0 - 30 - 10 + true + 0 + 30 + 10 -1 https://data.syncthing.net/newdata @@ -79,12 +82,18 @@ true 12 24 - true + false 5 true false - 0 1 - https://api.github.com/repos/syncthing/syncthing/releases?per_page=30 + https://upgrades.syncthing.net/meta.json + false + 10 + true + 0 + 30 + 10 + false