mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 12:44:22 +00:00
fix: keep latest IP for limit enforcement
This commit is contained in:
parent
987a6dd1e5
commit
074394a719
1 changed files with 13 additions and 14 deletions
|
|
@ -41,8 +41,8 @@ const defaultXrayAPIPort = 62789
|
||||||
//
|
//
|
||||||
// Without this eviction, an IP that connected once and then went away
|
// Without this eviction, an IP that connected once and then went away
|
||||||
// keeps sitting in the table with its old timestamp. Because the
|
// keeps sitting in the table with its old timestamp. Because the
|
||||||
// excess-IP selector sorts ascending ("oldest wins, newest loses") to
|
// excess-IP selector sorts ascending ("newest wins, oldest loses") to
|
||||||
// protect the original/current connections, that stale entry keeps
|
// protect the most recent connections, that stale entry keeps
|
||||||
// occupying a slot and the IP that is *actually* currently using the
|
// occupying a slot and the IP that is *actually* currently using the
|
||||||
// config gets classified as "new excess" and banned by fail2ban on
|
// config gets classified as "new excess" and banned by fail2ban on
|
||||||
// every single run — producing the continuous ban loop from #4077.
|
// every single run — producing the continuous ban loop from #4077.
|
||||||
|
|
@ -255,15 +255,13 @@ func mergeClientIps(old, new []IPWithTimestamp, staleCutoff int64) map[string]in
|
||||||
//
|
//
|
||||||
// only live ips count toward the per-client limit. historical ones stay
|
// only live ips count toward the per-client limit. historical ones stay
|
||||||
// in the db so the panel keeps showing them, but they must not take a
|
// in the db so the panel keeps showing them, but they must not take a
|
||||||
// protected slot. the 30min cutoff alone isn't tight enough: an ip that
|
// live slot or get re-banned. the 30min cutoff alone isn't tight enough:
|
||||||
// stopped connecting a few minutes ago still looks fresh to
|
// an ip that stopped connecting a few minutes ago still looks fresh to
|
||||||
// mergeClientIps, and since the over-limit picker sorts ascending and
|
// mergeClientIps, and without this split it would keep triggering
|
||||||
// keeps the oldest, those idle entries used to win the slot while the
|
// fail2ban even though it isn't currently connected. see #4077 / #4091.
|
||||||
// ip actually connecting got classified as excess and sent to fail2ban
|
|
||||||
// every tick. see #4077 / #4091.
|
|
||||||
//
|
//
|
||||||
// live is sorted ascending so the "protect original, ban newcomer"
|
// live is sorted ascending so we can drop the oldest entries first
|
||||||
// rule still holds when several ips are really connecting at once.
|
// while keeping the most recent ones (last IP wins).
|
||||||
func partitionLiveIps(ipMap map[string]int64, observedThisScan map[string]bool) (live, historical []IPWithTimestamp) {
|
func partitionLiveIps(ipMap map[string]int64, observedThisScan map[string]bool) (live, historical []IPWithTimestamp) {
|
||||||
live = make([]IPWithTimestamp, 0, len(observedThisScan))
|
live = make([]IPWithTimestamp, 0, len(observedThisScan))
|
||||||
historical = make([]IPWithTimestamp, 0, len(ipMap))
|
historical = make([]IPWithTimestamp, 0, len(ipMap))
|
||||||
|
|
@ -408,9 +406,10 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
||||||
if len(liveIps) > limitIp {
|
if len(liveIps) > limitIp {
|
||||||
shouldCleanLog = true
|
shouldCleanLog = true
|
||||||
|
|
||||||
// protect the oldest live ip, ban newcomers.
|
// keep the newest live ips, ban older ones.
|
||||||
keptLive = liveIps[:limitIp]
|
cutoff := len(liveIps) - limitIp
|
||||||
bannedLive := liveIps[limitIp:]
|
keptLive = liveIps[cutoff:]
|
||||||
|
bannedLive := liveIps[:cutoff]
|
||||||
|
|
||||||
// Open log file only when a ban entry needs to be written.
|
// Open log file only when a ban entry needs to be written.
|
||||||
// Use a local logger to avoid mutating the global log.* state,
|
// Use a local logger to avoid mutating the global log.* state,
|
||||||
|
|
@ -456,7 +455,7 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(j.disAllowedIps) > 0 {
|
if len(j.disAllowedIps) > 0 {
|
||||||
logger.Infof("[LIMIT_IP] Client %s: Kept %d live IPs, queued %d new IPs for fail2ban", clientEmail, len(keptLive), len(j.disAllowedIps))
|
logger.Infof("[LIMIT_IP] Client %s: Kept %d live IPs, queued %d old IPs for fail2ban", clientEmail, len(keptLive), len(j.disAllowedIps))
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldCleanLog
|
return shouldCleanLog
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue