From 5237337626ce5c28afb9a5d56e5f4fb305a0f73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Fri, 7 Jan 2022 11:19:17 +0100 Subject: [PATCH] cmd/syncthing: Add --skip-port-probing (fixes #8090) (#8099) * cmd/syncthing: Remove unnecessary function arguments. The openGUI() function does not need a device ID to work, and there is only one caller anyway which uses EmptyDeviceID. The loadOrDefaultConfig() function is always called with the same dummy values. * cmd/syncthing: Avoid misleading info messages from monitor process. In order to check whether panic reporting is enabled, the monitor process utilizes the loadOrDefaultConfig() function. In case there is no config file yet, info messages may be logged during creation if the config Wrapper, which is discarded immediately after. Stop using the DefaultConfig() utility function from lib/syncthing and directly generate a minimal config instead to avoid these. Add comments to loadOrDefaultConfig() explaining its limited purpose. * cmd/syncthing/generate: Always write updated config file. Previously, an existing config file was left untouched unless either of the --gui-user or --gui-password options was given. Remove that condition and simplify the checking code. * lib/config: Factor out ProbeFreePorts(). * cmd/syncthing: Add option --skip-port-probing. Applies to both the "generate" and "serve" subcommands, as well as the deprecated --generate option, just as the --no-default-folder flag. --- cmd/syncthing/cmdutil/options_common.go | 1 + cmd/syncthing/generate/generate.go | 6 +++--- cmd/syncthing/main.go | 4 ++-- lib/config/config.go | 10 ++++------ lib/syncthing/utils.go | 13 ++++++++----- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/cmd/syncthing/cmdutil/options_common.go b/cmd/syncthing/cmdutil/options_common.go index 34485e6a5..0751892d8 100644 --- a/cmd/syncthing/cmdutil/options_common.go +++ b/cmd/syncthing/cmdutil/options_common.go @@ -12,4 +12,5 @@ type CommonOptions struct { ConfDir string `name:"config" placeholder:"PATH" help:"Set configuration directory (config and keys)"` HomeDir string `name:"home" placeholder:"PATH" help:"Set configuration and data directory"` NoDefaultFolder bool `env:"STNODEFAULTFOLDER" help:"Don't create the \"default\" folder on first startup"` + SkipPortProbing bool `help:"Don't try to find free ports for GUI and listen addresses on first startup"` } diff --git a/cmd/syncthing/generate/generate.go b/cmd/syncthing/generate/generate.go index 4f5c2fa14..4df7c3d46 100644 --- a/cmd/syncthing/generate/generate.go +++ b/cmd/syncthing/generate/generate.go @@ -58,13 +58,13 @@ func (c *CLI) Run() error { c.GUIPassword = string(password) } - if err := Generate(c.ConfDir, c.GUIUser, c.GUIPassword, c.NoDefaultFolder); err != nil { + if err := Generate(c.ConfDir, c.GUIUser, c.GUIPassword, c.NoDefaultFolder, c.SkipPortProbing); err != nil { return fmt.Errorf("Failed to generate config and keys: %w", err) } return nil } -func Generate(confDir, guiUser, guiPassword string, noDefaultFolder bool) error { +func Generate(confDir, guiUser, guiPassword string, noDefaultFolder, skipPortProbing bool) error { dir, err := fs.ExpandTilde(confDir) if err != nil { return err @@ -92,7 +92,7 @@ func Generate(confDir, guiUser, guiPassword string, noDefaultFolder bool) error cfgFile := locations.Get(locations.ConfigFile) cfg, _, err := config.Load(cfgFile, myID, events.NoopLogger) if fs.IsNotExist(err) { - if cfg, err = syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder); err != nil { + if cfg, err = syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder, skipPortProbing); err != nil { return fmt.Errorf("create config: %w", err) } } else if err != nil { diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 07deb9be8..98175f80f 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -337,7 +337,7 @@ func (options serveOptions) Run() error { } if options.GenerateDir != "" { - if err := generate.Generate(options.GenerateDir, "", "", options.NoDefaultFolder); err != nil { + if err := generate.Generate(options.GenerateDir, "", "", options.NoDefaultFolder, options.SkipPortProbing); err != nil { l.Warnln("Failed to generate config and keys:", err) os.Exit(svcutil.ExitError.AsInt()) } @@ -551,7 +551,7 @@ func syncthingMain(options serveOptions) { evLogger := events.NewLogger() earlyService.Add(evLogger) - cfgWrapper, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, options.AllowNewerConfig, options.NoDefaultFolder) + cfgWrapper, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, options.AllowNewerConfig, options.NoDefaultFolder, options.SkipPortProbing) if err != nil { l.Warnln("Failed to initialize config:", err) os.Exit(svcutil.ExitError.AsInt()) diff --git a/lib/config/config.go b/lib/config/config.go index 67ea8a024..302cc760c 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -113,18 +113,16 @@ func New(myID protocol.DeviceID) Configuration { return cfg } -func NewWithFreePorts(myID protocol.DeviceID) (Configuration, error) { - cfg := New(myID) - +func (cfg *Configuration) ProbeFreePorts() error { port, err := getFreePort("127.0.0.1", DefaultGUIPort) if err != nil { - return Configuration{}, errors.Wrap(err, "get free port (GUI)") + return errors.Wrap(err, "get free port (GUI)") } cfg.GUI.RawAddress = fmt.Sprintf("127.0.0.1:%d", port) port, err = getFreePort("0.0.0.0", DefaultTCPPort) if err != nil { - return Configuration{}, errors.Wrap(err, "get free port (BEP)") + return errors.Wrap(err, "get free port (BEP)") } if port == DefaultTCPPort { cfg.Options.RawListenAddresses = []string{"default"} @@ -136,7 +134,7 @@ func NewWithFreePorts(myID protocol.DeviceID) (Configuration, error) { } } - return cfg, nil + return nil } type xmlConfiguration struct { diff --git a/lib/syncthing/utils.go b/lib/syncthing/utils.go index 5f59af2b6..bf4752494 100644 --- a/lib/syncthing/utils.go +++ b/lib/syncthing/utils.go @@ -59,9 +59,12 @@ func GenerateCertificate(certFile, keyFile string) (tls.Certificate, error) { return tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName, deviceCertLifetimeDays) } -func DefaultConfig(path string, myID protocol.DeviceID, evLogger events.Logger, noDefaultFolder bool) (config.Wrapper, error) { - newCfg, err := config.NewWithFreePorts(myID) - if err != nil { +func DefaultConfig(path string, myID protocol.DeviceID, evLogger events.Logger, noDefaultFolder, skipPortProbing bool) (config.Wrapper, error) { + newCfg := config.New(myID) + + if skipPortProbing { + l.Infoln("Using default network port numbers instead of probing for free ports") + } else if err := newCfg.ProbeFreePorts(); err != nil { return nil, err } @@ -84,11 +87,11 @@ func DefaultConfig(path string, myID protocol.DeviceID, evLogger events.Logger, // creates a default one, without the default folder if noDefaultFolder is ture. // Otherwise it checks the version, and archives and upgrades the config if // necessary or returns an error, if the version isn't compatible. -func LoadConfigAtStartup(path string, cert tls.Certificate, evLogger events.Logger, allowNewerConfig, noDefaultFolder bool) (config.Wrapper, error) { +func LoadConfigAtStartup(path string, cert tls.Certificate, evLogger events.Logger, allowNewerConfig, noDefaultFolder, skipPortProbing bool) (config.Wrapper, error) { myID := protocol.NewDeviceID(cert.Certificate[0]) cfg, originalVersion, err := config.Load(path, myID, evLogger) if fs.IsNotExist(err) { - cfg, err = DefaultConfig(path, myID, evLogger, noDefaultFolder) + cfg, err = DefaultConfig(path, myID, evLogger, noDefaultFolder, skipPortProbing) if err != nil { return nil, errors.Wrap(err, "failed to generate default config") }