mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-15 15:50:59 +00:00
fix(database): keep IP limits when the fail2ban probe is inconclusive (#6176)
* fix(database): keep IP limits when the fail2ban probe is inconclusive ResetIpLimitNoFail2ban clears limitIp on every client — inbound settings JSON and the clients table — whenever fail2banCanEnforce() returns false, then records itself in the seeder history so it never re-evaluates. The probe was a single `fail2ban-client -h` run, so it answered false both when fail2ban is genuinely absent and when the command merely failed that once: a panel that starts before fail2ban is up, or in a container where it is installed a moment later, permanently loses every configured limit with no log line and no way back. Separate the two. A missing binary still means "absent" and the cleanup runs as before; a binary that exists but will not run is reported as unknown, leaves the configured values untouched, logs why, and does not record the seeder, so the next start decides again. * test(database): cover fail2ban reset safeguards --------- Co-authored-by: n0ctal <293235942+n0ctal@users.noreply.github.com>
This commit is contained in:
+26
-5
@@ -1278,9 +1278,14 @@ func resetIpLimitsWithoutFail2ban() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if fail2banCanEnforce() {
|
||||
state, probeErr := fail2banEnforcementState()
|
||||
if state == fail2banEnforcing {
|
||||
return db.Create(&model.HistoryOfSeeders{SeederName: "ResetIpLimitNoFail2ban"}).Error
|
||||
}
|
||||
if state == fail2banUnknown {
|
||||
log.Printf("ResetIpLimitNoFail2ban: fail2ban-client present but not runnable (%v); keeping configured IP limits, will retry next start", probeErr)
|
||||
return nil
|
||||
}
|
||||
|
||||
var inbounds []model.Inbound
|
||||
if err := db.Find(&inbounds).Error; err != nil {
|
||||
@@ -1340,14 +1345,30 @@ func resetIpLimitsWithoutFail2ban() error {
|
||||
})
|
||||
}
|
||||
|
||||
func fail2banCanEnforce() bool {
|
||||
type fail2banState int
|
||||
|
||||
const (
|
||||
fail2banEnforcing fail2banState = iota
|
||||
fail2banAbsent
|
||||
fail2banUnknown
|
||||
)
|
||||
|
||||
// fail2banEnforcementState separates "fail2ban is not installed" from "the probe
|
||||
// itself failed", so a transient failure never drives an irreversible cleanup.
|
||||
func fail2banEnforcementState() (fail2banState, error) {
|
||||
if v, ok := os.LookupEnv("XUI_ENABLE_FAIL2BAN"); ok && v != "true" {
|
||||
return false
|
||||
return fail2banAbsent, nil
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
return false
|
||||
return fail2banAbsent, nil
|
||||
}
|
||||
return exec.CommandContext(context.Background(), "fail2ban-client", "-h").Run() == nil
|
||||
if _, err := exec.LookPath("fail2ban-client"); err != nil {
|
||||
return fail2banAbsent, nil
|
||||
}
|
||||
if err := exec.CommandContext(context.Background(), "fail2ban-client", "-h").Run(); err != nil {
|
||||
return fail2banUnknown, err
|
||||
}
|
||||
return fail2banEnforcing, nil
|
||||
}
|
||||
|
||||
func clearLegacyProxySettings() error {
|
||||
|
||||
Reference in New Issue
Block a user