-
+
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