mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-04-17 05:53:15 +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
|
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/.
|
// 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.
|
// Creates a backup of jail.local before migration. If a jail already exists in jail.d, jail.local takes precedence.
|
||||||
func MigrateJailsToJailD() error {
|
func MigrateJailsToJailD() error {
|
||||||
@@ -557,37 +522,6 @@ func TestLogpath(logpath string) ([]string, error) {
|
|||||||
return matches, nil
|
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.
|
// ExtractLogpathFromJailConfig extracts the logpath value from jail configuration content.
|
||||||
func ExtractLogpathFromJailConfig(jailContent string) string {
|
func ExtractLogpathFromJailConfig(jailContent string) string {
|
||||||
scanner := bufio.NewScanner(strings.NewReader(jailContent))
|
scanner := bufio.NewScanner(strings.NewReader(jailContent))
|
||||||
@@ -602,3 +536,29 @@ func ExtractLogpathFromJailConfig(jailContent string) string {
|
|||||||
}
|
}
|
||||||
return ""
|
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
|
config.DebugLog("GetJailFilterConfigHandler called (handlers.go)") // entry point
|
||||||
jail := c.Param("jail")
|
jail := c.Param("jail")
|
||||||
config.DebugLog("Jail name: %s", jail)
|
config.DebugLog("Jail name: %s", jail)
|
||||||
|
|
||||||
conn, err := resolveConnector(c)
|
conn, err := resolveConnector(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
config.DebugLog("Failed to resolve connector: %v", err)
|
config.DebugLog("Failed to resolve connector: %v", err)
|
||||||
@@ -678,28 +678,67 @@ func GetJailFilterConfigHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
config.DebugLog("Connector resolved: %s", conn.Server().Name)
|
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)
|
config.DebugLog("Loading filter config for jail: %s", jail)
|
||||||
filterCfg, err := conn.GetFilterConfig(c.Request.Context(), jail)
|
filterCfg, filterErr = conn.GetFilterConfig(c.Request.Context(), jail)
|
||||||
if err != nil {
|
if filterErr != nil {
|
||||||
config.DebugLog("Failed to load filter config: %v", err)
|
config.DebugLog("Failed to load filter config with jail name, trying to find filter from jail config: %v", filterErr)
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load filter config: " + err.Error()})
|
|
||||||
return
|
// 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("Filter config loaded, length: %d", len(filterCfg))
|
||||||
|
|
||||||
config.DebugLog("Loading jail config for jail: %s", jail)
|
// Load jail config if not already loaded
|
||||||
jailCfg, err := conn.GetJailConfig(c.Request.Context(), jail)
|
if !jailCfgLoaded {
|
||||||
if err != nil {
|
config.DebugLog("Loading jail config for jail: %s", jail)
|
||||||
config.DebugLog("Failed to load jail config: %v", err)
|
var jailErr error
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load jail config: " + err.Error()})
|
jailCfg, jailErr = conn.GetJailConfig(c.Request.Context(), jail)
|
||||||
return
|
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{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"jail": jail,
|
"jail": jail,
|
||||||
"filter": filterCfg,
|
"filter": filterCfg,
|
||||||
"jailConfig": jailCfg,
|
"jailConfig": jailCfg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -717,7 +756,7 @@ func SetJailFilterConfigHandler(c *gin.Context) {
|
|||||||
config.DebugLog("SetJailFilterConfigHandler called (handlers.go)") // entry point
|
config.DebugLog("SetJailFilterConfigHandler called (handlers.go)") // entry point
|
||||||
jail := c.Param("jail")
|
jail := c.Param("jail")
|
||||||
config.DebugLog("Jail name: %s", jail)
|
config.DebugLog("Jail name: %s", jail)
|
||||||
|
|
||||||
conn, err := resolveConnector(c)
|
conn, err := resolveConnector(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
config.DebugLog("Failed to resolve connector: %v", err)
|
config.DebugLog("Failed to resolve connector: %v", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user