|
@@ -35,6 +35,7 @@ type CheckClientIpJob struct {
|
|
|
disAllowedIps []string
|
|
disAllowedIps []string
|
|
|
bannedSeen map[string]int64
|
|
bannedSeen map[string]int64
|
|
|
xrayService service.XrayService
|
|
xrayService service.XrayService
|
|
|
|
|
+ allowlist ipLimitAllowlist
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var job *CheckClientIpJob
|
|
var job *CheckClientIpJob
|
|
@@ -67,7 +68,13 @@ func (j *CheckClientIpJob) Run() {
|
|
|
if hasLimit {
|
|
if hasLimit {
|
|
|
f2bInstalled = j.checkFail2BanInstalled()
|
|
f2bInstalled = j.checkFail2BanInstalled()
|
|
|
}
|
|
}
|
|
|
- j.processObserved(observed, j.resolveEnforce(hasLimit, f2bInstalled), true)
|
|
|
|
|
|
|
+ // Read only when the limit is actually applied: this runs every 10s and
|
|
|
|
|
+ // most panels carry no IP limit at all.
|
|
|
|
|
+ enforce := j.resolveEnforce(hasLimit, f2bInstalled)
|
|
|
|
|
+ if enforce {
|
|
|
|
|
+ j.allowlist = j.loadAllowlist()
|
|
|
|
|
+ }
|
|
|
|
|
+ j.processObserved(observed, enforce, true)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// resolveEnforce decides whether limits can actually be enforced this run.
|
|
// resolveEnforce decides whether limits can actually be enforced this run.
|
|
@@ -126,6 +133,18 @@ func (j *CheckClientIpJob) hasLimitIp() bool {
|
|
|
return err == nil && probe > 0
|
|
return err == nil && probe > 0
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// loadAllowlist reads the operator's trusted addresses once per scan; a bad
|
|
|
|
|
+// read leaves the list empty, which enforces the limit as before rather than
|
|
|
|
|
+// silently exempting everyone.
|
|
|
|
|
+func (j *CheckClientIpJob) loadAllowlist() ipLimitAllowlist {
|
|
|
|
|
+ raw, err := (&service.SettingService{}).GetIpLimitAllowlist()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ logger.Warning("[LimitIP] could not read the allowlist, enforcing without it:", err)
|
|
|
|
|
+ return ipLimitAllowlist{}
|
|
|
|
|
+ }
|
|
|
|
|
+ return parseIpLimitAllowlist(raw)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const ipScanChunk = 400
|
|
const ipScanChunk = 400
|
|
|
|
|
|
|
|
func chunkEmails(s []string, size int) [][]string {
|
|
func chunkEmails(s []string, size int) [][]string {
|
|
@@ -510,7 +529,11 @@ func (j *CheckClientIpJob) updateInboundClientIps(tx *gorm.DB, inboundClientIps
|
|
|
j.disAllowedIps = []string{}
|
|
j.disAllowedIps = []string{}
|
|
|
|
|
|
|
|
// historical db-only ips are excluded from this count on purpose.
|
|
// historical db-only ips are excluded from this count on purpose.
|
|
|
- keptLive, bannedLive := selectIpsToBan(liveIps, limitIp)
|
|
|
|
|
|
|
+ limitedIps, allowedIps := j.allowlist.split(liveIps)
|
|
|
|
|
+ keptLive, bannedLive := selectIpsToBan(limitedIps, limitIp)
|
|
|
|
|
+ // Allowlisted addresses stay connected and out of the count: charging them
|
|
|
|
|
+ // against the limit would still cut the shared network the entry protects.
|
|
|
|
|
+ keptLive = append(keptLive, allowedIps...)
|
|
|
actionable := j.filterAdvancedSinceLastBan(clientEmail, bannedLive)
|
|
actionable := j.filterAdvancedSinceLastBan(clientEmail, bannedLive)
|
|
|
if len(actionable) > 0 {
|
|
if len(actionable) > 0 {
|
|
|
shouldCleanLog = true
|
|
shouldCleanLog = true
|