diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index fdc2e912..3b6d0be1 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -206,7 +206,13 @@ func (s *apiService) getListener(guiCfg config.GUIConfiguration) (net.Listener, }, } - rawListener, err := net.Listen("tcp", guiCfg.Address()) + if guiCfg.Network() == "unix" { + // When listening on a UNIX socket we should unlink before bind, + // lest we get a "bind: address already in use". We don't + // particularly care if this succeeds or not. + os.Remove(guiCfg.Address()) + } + rawListener, err := net.Listen(guiCfg.Network(), guiCfg.Address()) if err != nil { return nil, err } @@ -420,6 +426,9 @@ func (s *apiService) String() string { } func (s *apiService) VerifyConfiguration(from, to config.Configuration) error { + if to.GUI.Network() != "tcp" { + return nil + } _, err := net.ResolveTCPAddr("tcp", to.GUI.Address()) return err } @@ -980,6 +989,7 @@ func (s *apiService) getSystemStatus(w http.ResponseWriter, r *http.Request) { res["urVersionMax"] = usageReportVersion res["uptime"] = int(time.Since(startTime).Seconds()) res["startTime"] = startTime + res["guiAddressOverridden"] = s.cfg.GUI().IsOverridden() sendJSON(w, res) } diff --git a/gui/default/syncthing/settings/settingsModalView.html b/gui/default/syncthing/settings/settingsModalView.html index 9f208efa..982e1b0b 100644 --- a/gui/default/syncthing/settings/settingsModalView.html +++ b/gui/default/syncthing/settings/settingsModalView.html @@ -111,7 +111,11 @@
+ + The GUI address is overridden by startup options. Changes here will not take effect while the override is in place. +
+Enter a non-privileged port number (1024 - 65535).
diff --git a/lib/config/guiconfiguration.go b/lib/config/guiconfiguration.go index 58a3edf2..fb646721 100644 --- a/lib/config/guiconfiguration.go +++ b/lib/config/guiconfiguration.go @@ -31,6 +31,10 @@ func (c GUIConfiguration) IsAuthEnabled() bool { return c.AuthMode == AuthModeLDAP || (len(c.User) > 0 && len(c.Password) > 0) } +func (c GUIConfiguration) IsOverridden() bool { + return os.Getenv("STGUIADDRESS") != "" +} + func (c GUIConfiguration) Address() string { if override := os.Getenv("STGUIADDRESS"); override != "" { // This value may be of the form "scheme://address:port" or just @@ -43,6 +47,9 @@ func (c GUIConfiguration) Address() string { if err != nil { return override } + if strings.HasPrefix(url.Scheme, "unix") { + return url.Path + } return url.Host } @@ -52,14 +59,39 @@ func (c GUIConfiguration) Address() string { return c.RawAddress } +func (c GUIConfiguration) Network() string { + if override := os.Getenv("STGUIADDRESS"); strings.Contains(override, "/") { + url, err := url.Parse(override) + if err != nil { + return "tcp" + } + if strings.HasPrefix(url.Scheme, "unix") { + return "unix" + } + } + if strings.HasPrefix(c.RawAddress, "/") { + return "unix" + } + return "tcp" +} + func (c GUIConfiguration) UseTLS() bool { - if override := os.Getenv("STGUIADDRESS"); override != "" && strings.HasPrefix(override, "http") { - return strings.HasPrefix(override, "https:") + if override := os.Getenv("STGUIADDRESS"); override != "" { + if strings.HasPrefix(override, "http") { + return strings.HasPrefix(override, "https:") + } + if strings.HasPrefix(override, "unix") { + return strings.HasPrefix(override, "unixs:") + } } return c.RawUseTLS } func (c GUIConfiguration) URL() string { + if strings.HasPrefix(c.RawAddress, "/") { + return "unix://" + c.RawAddress + } + u := url.URL{ Scheme: "http", Host: c.Address(),