mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-08 14:36:13 +00:00
fix(fail2ban): fix banning regression and Docker zero-jail issue
- DockerEntrypoint.sh: create jail.d/filter.d/action.d config files before starting fail2ban so Docker containers no longer start with 0 active jails (fixes #4134) - x-ui.sh create_iplimit_jails: lower maxretry from 2 to 1 so fail2ban bans on the first log entry; with maxretry=2 and the partitionLiveIps logic the second occurrence could arrive after the 32 s findtime window, silently preventing any ban (fixes #4163) - x-ui.sh: fix datepattern (%%Y -> %Y) so fail2ban parses the Go log timestamp correctly instead of looking for a literal %%Y string - x-ui.sh / DockerEntrypoint.sh: fix date command in actionban / actionunban echo (%%Y -> %Y) so the ban log records actual dates - check_client_ip_job.go: replace log.SetOutput / log.SetFlags on the global standard-library logger with a local log.New instance, eliminating the dangling closed-file-handle between calls and stopping unrelated stdlib log output from polluting 3xipl.log Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -403,16 +403,6 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
||||
shouldCleanLog := false
|
||||
j.disAllowedIps = []string{}
|
||||
|
||||
// Open log file
|
||||
logIpFile, err := os.OpenFile(xray.GetIPLimitLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to open IP limit log file: %s", err)
|
||||
return false
|
||||
}
|
||||
defer logIpFile.Close()
|
||||
log.SetOutput(logIpFile)
|
||||
log.SetFlags(log.LstdFlags)
|
||||
|
||||
// historical db-only ips are excluded from this count on purpose.
|
||||
var keptLive []IPWithTimestamp
|
||||
if len(liveIps) > limitIp {
|
||||
@@ -422,13 +412,25 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
||||
keptLive = liveIps[:limitIp]
|
||||
bannedLive := liveIps[limitIp:]
|
||||
|
||||
// Open log file only when a ban entry needs to be written.
|
||||
// Use a local logger to avoid mutating the global log.* state,
|
||||
// which would redirect all standard-library logging to this file
|
||||
// and leave a dangling closed-file handle after the defer fires.
|
||||
logIpFile, err := os.OpenFile(xray.GetIPLimitLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to open IP limit log file: %s", err)
|
||||
return false
|
||||
}
|
||||
defer logIpFile.Close()
|
||||
ipLogger := log.New(logIpFile, "", log.LstdFlags)
|
||||
|
||||
// log format is load-bearing: x-ui.sh create_iplimit_jails builds
|
||||
// filter.d/3x-ipl.conf with
|
||||
// failregex = \[LIMIT_IP\]\s*Email\s*=\s*<F-USER>.+</F-USER>\s*\|\|\s*Disconnecting OLD IP\s*=\s*<ADDR>\s*\|\|\s*Timestamp\s*=\s*\d+
|
||||
// don't change the wording.
|
||||
for _, ipTime := range bannedLive {
|
||||
j.disAllowedIps = append(j.disAllowedIps, ipTime.IP)
|
||||
log.Printf("[LIMIT_IP] Email = %s || Disconnecting OLD IP = %s || Timestamp = %d", clientEmail, ipTime.IP, ipTime.Timestamp)
|
||||
ipLogger.Printf("[LIMIT_IP] Email = %s || Disconnecting OLD IP = %s || Timestamp = %d", clientEmail, ipTime.IP, ipTime.Timestamp)
|
||||
}
|
||||
|
||||
// force xray to drop existing connections from banned ips
|
||||
|
||||
Reference in New Issue
Block a user