mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-04-15 05:03:14 +02:00
Fix case if a jail have a custom filter set, that isn't the same name as the jail is
This commit is contained in:
@@ -191,41 +191,6 @@ func UpdateJailEnabledStates(updates map[string]bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateJailConfigFile updates a single jail configuration file with the new enabled states.
|
||||
func updateJailConfigFile(path string, updates map[string]bool) error {
|
||||
input, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := strings.Split(string(input), "\n")
|
||||
var outputLines []string
|
||||
var currentJail string
|
||||
for _, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if strings.HasPrefix(trimmed, "[") && strings.HasSuffix(trimmed, "]") {
|
||||
currentJail = strings.Trim(trimmed, "[]")
|
||||
outputLines = append(outputLines, line)
|
||||
} else if strings.HasPrefix(trimmed, "enabled") {
|
||||
if val, ok := updates[currentJail]; ok {
|
||||
outputLines = append(outputLines, fmt.Sprintf("enabled = %t", val))
|
||||
// Remove the update from map to mark it as processed.
|
||||
delete(updates, currentJail)
|
||||
} else {
|
||||
outputLines = append(outputLines, line)
|
||||
}
|
||||
} else {
|
||||
outputLines = append(outputLines, line)
|
||||
}
|
||||
}
|
||||
// For any jails in updates that did not have an "enabled" line, append it.
|
||||
for jail, val := range updates {
|
||||
outputLines = append(outputLines, fmt.Sprintf("[%s]", jail))
|
||||
outputLines = append(outputLines, fmt.Sprintf("enabled = %t", val))
|
||||
}
|
||||
newContent := strings.Join(outputLines, "\n")
|
||||
return os.WriteFile(path, []byte(newContent), 0644)
|
||||
}
|
||||
|
||||
// MigrateJailsToJailD migrates all non-DEFAULT jails from jail.local to individual files in jail.d/.
|
||||
// Creates a backup of jail.local before migration. If a jail already exists in jail.d, jail.local takes precedence.
|
||||
func MigrateJailsToJailD() error {
|
||||
@@ -557,37 +522,6 @@ func TestLogpath(logpath string) ([]string, error) {
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
// parseJailSection extracts the logpath from a jail configuration content.
|
||||
func parseJailSection(content string, jailName string) (string, error) {
|
||||
// This function can be used to extract specific settings from jail config
|
||||
// For now, we'll use it to find logpath
|
||||
scanner := bufio.NewScanner(strings.NewReader(content))
|
||||
var inTargetJail bool
|
||||
var jailContent strings.Builder
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
trimmed := strings.TrimSpace(line)
|
||||
|
||||
if strings.HasPrefix(trimmed, "[") && strings.HasSuffix(trimmed, "]") {
|
||||
currentJail := strings.Trim(trimmed, "[]")
|
||||
if currentJail == jailName {
|
||||
inTargetJail = true
|
||||
jailContent.Reset()
|
||||
jailContent.WriteString(line)
|
||||
jailContent.WriteString("\n")
|
||||
} else {
|
||||
inTargetJail = false
|
||||
}
|
||||
} else if inTargetJail {
|
||||
jailContent.WriteString(line)
|
||||
jailContent.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
return jailContent.String(), scanner.Err()
|
||||
}
|
||||
|
||||
// ExtractLogpathFromJailConfig extracts the logpath value from jail configuration content.
|
||||
func ExtractLogpathFromJailConfig(jailContent string) string {
|
||||
scanner := bufio.NewScanner(strings.NewReader(jailContent))
|
||||
@@ -602,3 +536,29 @@ func ExtractLogpathFromJailConfig(jailContent string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ExtractFilterFromJailConfig extracts the filter name from jail configuration content.
|
||||
// Handles formats like: filter = sshd, filter = sshd[mode=aggressive], etc.
|
||||
// Returns the base filter name (without parameters in brackets).
|
||||
func ExtractFilterFromJailConfig(jailContent string) string {
|
||||
scanner := bufio.NewScanner(strings.NewReader(jailContent))
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
// Skip comments
|
||||
if strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(strings.ToLower(line), "filter") {
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) == 2 {
|
||||
filterValue := strings.TrimSpace(parts[1])
|
||||
// Extract base filter name (before [ if present)
|
||||
if idx := strings.Index(filterValue, "["); idx >= 0 {
|
||||
filterValue = filterValue[:idx]
|
||||
}
|
||||
return strings.TrimSpace(filterValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -670,7 +670,7 @@ func GetJailFilterConfigHandler(c *gin.Context) {
|
||||
config.DebugLog("GetJailFilterConfigHandler called (handlers.go)") // entry point
|
||||
jail := c.Param("jail")
|
||||
config.DebugLog("Jail name: %s", jail)
|
||||
|
||||
|
||||
conn, err := resolveConnector(c)
|
||||
if err != nil {
|
||||
config.DebugLog("Failed to resolve connector: %v", err)
|
||||
@@ -678,28 +678,67 @@ func GetJailFilterConfigHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
config.DebugLog("Connector resolved: %s", conn.Server().Name)
|
||||
|
||||
|
||||
var filterCfg string
|
||||
var jailCfg string
|
||||
var jailCfgLoaded bool
|
||||
var filterErr error
|
||||
|
||||
// First, try to load filter config using jail name
|
||||
config.DebugLog("Loading filter config for jail: %s", jail)
|
||||
filterCfg, err := conn.GetFilterConfig(c.Request.Context(), jail)
|
||||
if err != nil {
|
||||
config.DebugLog("Failed to load filter config: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load filter config: " + err.Error()})
|
||||
return
|
||||
filterCfg, filterErr = conn.GetFilterConfig(c.Request.Context(), jail)
|
||||
if filterErr != nil {
|
||||
config.DebugLog("Failed to load filter config with jail name, trying to find filter from jail config: %v", filterErr)
|
||||
|
||||
// Load jail config first to check for custom filter directive
|
||||
var jailErr error
|
||||
jailCfg, jailErr = conn.GetJailConfig(c.Request.Context(), jail)
|
||||
if jailErr != nil {
|
||||
config.DebugLog("Failed to load jail config: %v", jailErr)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load filter config: " + filterErr.Error() + ". Also failed to load jail config: " + jailErr.Error()})
|
||||
return
|
||||
}
|
||||
jailCfgLoaded = true
|
||||
config.DebugLog("Jail config loaded, length: %d", len(jailCfg))
|
||||
|
||||
// Extract filter name from jail config
|
||||
filterName := fail2ban.ExtractFilterFromJailConfig(jailCfg)
|
||||
if filterName == "" {
|
||||
config.DebugLog("No filter directive found in jail config")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load filter config: " + filterErr.Error() + ". No filter directive found in jail config."})
|
||||
return
|
||||
}
|
||||
|
||||
config.DebugLog("Found filter directive in jail config: %s, trying to load that filter", filterName)
|
||||
// Try loading the filter specified in jail config
|
||||
filterCfg, filterErr = conn.GetFilterConfig(c.Request.Context(), filterName)
|
||||
if filterErr != nil {
|
||||
config.DebugLog("Failed to load filter config for %s: %v", filterName, filterErr)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": fmt.Sprintf("Failed to load filter config. Tried '%s' (jail name) and '%s' (from jail config), both failed. Last error: %v", jail, filterName, filterErr),
|
||||
})
|
||||
return
|
||||
}
|
||||
config.DebugLog("Successfully loaded filter config for %s (from jail config directive)", filterName)
|
||||
}
|
||||
config.DebugLog("Filter config loaded, length: %d", len(filterCfg))
|
||||
|
||||
config.DebugLog("Loading jail config for jail: %s", jail)
|
||||
jailCfg, err := conn.GetJailConfig(c.Request.Context(), jail)
|
||||
if err != nil {
|
||||
config.DebugLog("Failed to load jail config: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load jail config: " + err.Error()})
|
||||
return
|
||||
|
||||
// Load jail config if not already loaded
|
||||
if !jailCfgLoaded {
|
||||
config.DebugLog("Loading jail config for jail: %s", jail)
|
||||
var jailErr error
|
||||
jailCfg, jailErr = conn.GetJailConfig(c.Request.Context(), jail)
|
||||
if jailErr != nil {
|
||||
config.DebugLog("Failed to load jail config: %v", jailErr)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load jail config: " + jailErr.Error()})
|
||||
return
|
||||
}
|
||||
config.DebugLog("Jail config loaded, length: %d", len(jailCfg))
|
||||
}
|
||||
config.DebugLog("Jail config loaded, length: %d", len(jailCfg))
|
||||
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"jail": jail,
|
||||
"filter": filterCfg,
|
||||
"jail": jail,
|
||||
"filter": filterCfg,
|
||||
"jailConfig": jailCfg,
|
||||
})
|
||||
}
|
||||
@@ -717,7 +756,7 @@ func SetJailFilterConfigHandler(c *gin.Context) {
|
||||
config.DebugLog("SetJailFilterConfigHandler called (handlers.go)") // entry point
|
||||
jail := c.Param("jail")
|
||||
config.DebugLog("Jail name: %s", jail)
|
||||
|
||||
|
||||
conn, err := resolveConnector(c)
|
||||
if err != nil {
|
||||
config.DebugLog("Failed to resolve connector: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user