fix(job): expire stored client IPs of offline clients

ipStaleAfterSeconds was only applied while a row was being rewritten, and
rows are only rewritten for clients present in the current online scan. A
client that stopped connecting therefore kept its last addresses forever
in inbound_client_ips, and node_client_ips rows (including those of
deleted clients) were never revisited at all. Sweep both tables every five
minutes, dropping entries past the cutoff and deleting rows that end up
empty. The sweep runs ahead of the fail2ban and api-mode gates so
retention holds even on panels that collect nothing.

Closes #6286
This commit is contained in:
Sanaei
2026-08-24 13:27:40 +02:00
parent 2d30ab3ada
commit 103b0dfe8d
4 changed files with 158 additions and 0 deletions
+18
View File
@@ -36,6 +36,7 @@ type CheckClientIpJob struct {
bannedSeen map[string]int64
xrayService service.XrayService
allowlist ipLimitAllowlist
lastIpPrune int64
}
var job *CheckClientIpJob
@@ -44,6 +45,9 @@ const defaultXrayAPIPort = 62789
const ipStaleAfterSeconds = int64(30 * 60)
// pruneStaleIpRows cadence; the scan itself cannot prune offline clients' rows.
const ipPruneIntervalSeconds = int64(5 * 60)
// NewCheckClientIpJob creates a new client IP monitoring job instance.
func NewCheckClientIpJob() *CheckClientIpJob {
job = new(CheckClientIpJob)
@@ -51,6 +55,7 @@ func NewCheckClientIpJob() *CheckClientIpJob {
}
func (j *CheckClientIpJob) Run() {
j.pruneStaleIpRows()
observed, apiMode := j.collectFromOnlineAPI()
if !apiMode {
// xray is down or predates the online-stats API. There is no access-log
@@ -769,3 +774,16 @@ func (j *CheckClientIpJob) getInboundByEmail(clientEmail string) (*model.Inbound
return nil, err
}
// Runs before the fail2ban/apiMode gates: retention must hold for stored rows
// even while nothing is being collected.
func (j *CheckClientIpJob) pruneStaleIpRows() {
now := time.Now().Unix()
if now-j.lastIpPrune < ipPruneIntervalSeconds {
return
}
j.lastIpPrune = now
if err := (&service.InboundService{}).PruneStaleClientIps(); err != nil {
logger.Warning("prune stale client ip rows failed:", err)
}
}