Implement config-change check, before doing reload

This commit is contained in:
Michael Reber
2025-01-26 19:58:36 +01:00
parent 0470f2f26f
commit 6e11189025

View File

@@ -7,13 +7,12 @@ import (
"sync" "sync"
) )
// UISettings holds both the UI settings (like language) and // AppSettings holds both the UI settings (like language) and
// relevant Fail2ban jail/local config options. // relevant Fail2ban jail/local config options.
type UISettings struct { type AppSettings struct {
// UI-specific Language string `json:"language"`
Language string `json:"language"` ReloadNeeded bool `json:"reloadNeeded"`
// Whether a reload is needed (e.g. user changed filter or jail settings). AlertCountries []string `json:"alertCountries"`
ReloadNeeded bool `json:"reloadNeeded"`
// These mirror some Fail2ban [DEFAULT] section parameters from jail.local // These mirror some Fail2ban [DEFAULT] section parameters from jail.local
BantimeIncrement bool `json:"bantimeIncrement"` BantimeIncrement bool `json:"bantimeIncrement"`
@@ -30,7 +29,7 @@ const settingsFile = "fail2ban-ui-settings.json"
// in-memory copy of settings // in-memory copy of settings
var ( var (
currentSettings UISettings currentSettings AppSettings
settingsLock sync.RWMutex settingsLock sync.RWMutex
) )
@@ -55,9 +54,10 @@ func setDefaults() {
settingsLock.Lock() settingsLock.Lock()
defer settingsLock.Unlock() defer settingsLock.Unlock()
currentSettings = UISettings{ currentSettings = AppSettings{
Language: "en", Language: "en",
ReloadNeeded: false, ReloadNeeded: false,
AlertCountries: []string{"all"},
BantimeIncrement: true, BantimeIncrement: true,
IgnoreIP: "127.0.0.1/8 ::1 172.16.10.1/24", IgnoreIP: "127.0.0.1/8 ::1 172.16.10.1/24",
@@ -79,7 +79,7 @@ func loadSettings() error {
return err return err
} }
var s UISettings var s AppSettings
if err := json.Unmarshal(data, &s); err != nil { if err := json.Unmarshal(data, &s); err != nil {
return err return err
} }
@@ -103,33 +103,54 @@ func saveSettings() error {
} }
// GetSettings returns a copy of the current settings // GetSettings returns a copy of the current settings
func GetSettings() UISettings { func GetSettings() AppSettings {
settingsLock.RLock() settingsLock.RLock()
defer settingsLock.RUnlock() defer settingsLock.RUnlock()
return currentSettings return currentSettings
} }
// UpdateSettings modifies the in-memory settings, sets ReloadNeeded if required, then saves to disk. // MarkReloadNeeded sets reloadNeeded = true and saves JSON
// Optionally, we can detect changes that require a reload vs. changes that don't. func MarkReloadNeeded() error {
func UpdateSettings(new UISettings) (UISettings, error) {
settingsLock.Lock() settingsLock.Lock()
defer settingsLock.Unlock() defer settingsLock.Unlock()
// If user changed certain fields that require a Fail2ban reload, set ReloadNeeded = true. currentSettings.ReloadNeeded = true
// For example, if any of these fields changed: return saveSettings()
reloadNeededBefore := currentSettings.ReloadNeeded }
if currentSettings.BantimeIncrement != new.BantimeIncrement || // MarkReloadDone sets reloadNeeded = false and saves JSON
currentSettings.IgnoreIP != new.IgnoreIP || func MarkReloadDone() error {
currentSettings.Bantime != new.Bantime || settingsLock.Lock()
currentSettings.Findtime != new.Findtime || defer settingsLock.Unlock()
currentSettings.Maxretry != new.Maxretry ||
currentSettings.Destemail != new.Destemail || currentSettings.ReloadNeeded = false
currentSettings.Sender != new.Sender { return saveSettings()
}
// UpdateSettings merges new settings with old and sets reloadNeeded if needed
func UpdateSettings(new AppSettings) (AppSettings, error) {
settingsLock.Lock()
defer settingsLock.Unlock()
old := currentSettings
// If certain fields change, we mark reload needed
if old.BantimeIncrement != new.BantimeIncrement ||
old.IgnoreIP != new.IgnoreIP ||
old.Bantime != new.Bantime ||
old.Findtime != new.Findtime ||
old.Maxretry != new.Maxretry ||
old.Destemail != new.Destemail ||
old.Sender != new.Sender {
new.ReloadNeeded = true new.ReloadNeeded = true
} else { } else {
// preserve previous ReloadNeeded if it was already true // preserve previous ReloadNeeded if it was already true
new.ReloadNeeded = new.ReloadNeeded || reloadNeededBefore new.ReloadNeeded = new.ReloadNeeded || old.ReloadNeeded
}
// Countries change? Currently also requires a reload
if !equalStringSlices(old.AlertCountries, new.AlertCountries) {
new.ReloadNeeded = true
} }
currentSettings = new currentSettings = new
@@ -141,10 +162,18 @@ func UpdateSettings(new UISettings) (UISettings, error) {
return currentSettings, nil return currentSettings, nil
} }
// MarkReloadDone sets ReloadNeeded = false after the user reloaded fail2ban func equalStringSlices(a, b []string) bool {
func MarkReloadDone() error { if len(a) != len(b) {
settingsLock.Lock() return false
defer settingsLock.Unlock() }
currentSettings.ReloadNeeded = false m := make(map[string]bool)
return saveSettings() for _, x := range a {
m[x] = false
}
for _, x := range b {
if _, ok := m[x]; !ok {
return false
}
}
return true
} }