From 8c84909c95bd1d81b46884c39c43f4547ff957c5 Mon Sep 17 00:00:00 2001 From: Michael Reber Date: Thu, 27 Feb 2025 14:03:08 +0100 Subject: [PATCH] workaround for the restart command may fail in container (since fail2ban runs on the host) --- internal/config/settings.go | 31 +++++++------------------------ internal/fail2ban/client.go | 6 ++++++ pkg/web/handlers.go | 19 ++++++++++++++----- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/internal/config/settings.go b/internal/config/settings.go index 45f0ff9..887b178 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -191,6 +191,8 @@ func initializeFromJailFile() error { // initializeFail2banAction writes a custom action configuration for Fail2ban to use AlertCountries. func initializeFail2banAction() error { + DebugLog("----------------------------") + DebugLog("Running initial initializeFail2banAction()") // entry point // Ensure the jail.local is configured correctly if err := setupGeoCustomAction(); err != nil { fmt.Println("Error setup GeoCustomAction in jail.local:", err) @@ -205,6 +207,7 @@ func initializeFail2banAction() error { // setupGeoCustomAction checks and replaces the default action in jail.local with our from fail2ban-UI func setupGeoCustomAction() error { + DebugLog("Running initial setupGeoCustomAction()") // entry point file, err := os.Open(jailFile) if err != nil { // Fallback: Copy default file if jail.local is not found @@ -284,6 +287,7 @@ func copyFile(src, dst string) error { // ensureJailDConfig checks if the jail.d file exists and creates it if necessary func ensureJailDConfig() error { + DebugLog("Running initial ensureJailDConfig()") // entry point // Check if the file already exists if _, err := os.Stat(jailDFile); err == nil { // File already exists, do nothing @@ -310,6 +314,8 @@ action_mwlg = %(action_)s // writeFail2banAction creates or updates the action file with the AlertCountries. func writeFail2banAction() error { + DebugLog("Running initial writeFail2banAction()") // entry point + DebugLog("----------------------------") // Define the Fail2Ban action file content actionConfig := `[INCLUDES] @@ -395,7 +401,7 @@ func saveSettings() error { if err != nil { DebugLog("Error writing to file: %v", err) // Debug } - // Update the Fail2ban action file + // Write again the Fail2ban-UI action file (in the future not used anymore) return writeFail2banAction() } @@ -439,8 +445,6 @@ func UpdateSettings(new AppSettings) (AppSettings, error) { old.Bantime != new.Bantime || old.Findtime != new.Findtime || //old.Maxretry != new.Maxretry || - old.Destemail != new.Destemail || - //old.Sender != new.Sender { old.Maxretry != new.Maxretry { new.RestartNeeded = true } else { @@ -448,11 +452,6 @@ func UpdateSettings(new AppSettings) (AppSettings, error) { new.RestartNeeded = new.RestartNeeded || old.RestartNeeded } - // Countries change? Currently also requires a reload - if !equalStringSlices(old.AlertCountries, new.AlertCountries) { - new.RestartNeeded = true - } - currentSettings = new DebugLog("New settings applied: %v", currentSettings) // Log settings applied @@ -464,19 +463,3 @@ func UpdateSettings(new AppSettings) (AppSettings, error) { fmt.Println("Settings saved to file successfully") // Log save success return currentSettings, nil } - -func equalStringSlices(a, b []string) bool { - if len(a) != len(b) { - return false - } - m := make(map[string]bool) - for _, x := range a { - m[x] = false - } - for _, x := range b { - if _, ok := m[x]; !ok { - return false - } - } - return true -} diff --git a/internal/fail2ban/client.go b/internal/fail2ban/client.go index 49ae4bb..6ed4b07 100644 --- a/internal/fail2ban/client.go +++ b/internal/fail2ban/client.go @@ -19,6 +19,7 @@ package fail2ban import ( "errors" "fmt" + "os" "os/exec" "strings" "time" @@ -152,6 +153,11 @@ func ReloadFail2ban() error { // RestartFail2ban restarts the Fail2ban service. func RestartFail2ban() error { + + // Check if running inside a container. + if _, container := os.LookupEnv("CONTAINER"); container { + return fmt.Errorf("restart not supported inside container; please restart fail2ban on the host") + } cmd := "systemctl restart fail2ban" out, err := execCommand(cmd) if err != nil { diff --git a/pkg/web/handlers.go b/pkg/web/handlers.go index 4044002..4abde35 100644 --- a/pkg/web/handlers.go +++ b/pkg/web/handlers.go @@ -439,13 +439,22 @@ func RestartFail2banHandler(c *gin.Context) { // return // } - // Then restart - if err := fail2ban.RestartFail2ban(); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return + // Attempt to restart the fail2ban service. + restartErr := fail2ban.RestartFail2ban() + if restartErr != nil { + // Check if running inside a container. + if _, container := os.LookupEnv("CONTAINER"); container { + // In a container, the restart command may fail (since fail2ban runs on the host). + // Log the error and continue, so we can mark the restart as done. + log.Printf("Warning: restart failed inside container (expected behavior): %v", restartErr) + } else { + // On the host, a restart error is not acceptable. + c.JSON(http.StatusInternalServerError, gin.H{"error": restartErr.Error()}) + return + } } - // We set restart done in config + // Only call MarkRestartDone if we either successfully restarted the service or we are in a container. if err := config.MarkRestartDone(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return