platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
142
selective-vpn-api/app/resolver_dns_cooldown.go
Normal file
142
selective-vpn-api/app/resolver_dns_cooldown.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newDNSRunCooldown() *dnsRunCooldown {
|
||||
enabled := true
|
||||
switch strings.ToLower(strings.TrimSpace(os.Getenv("RESOLVE_DNS_COOLDOWN_ENABLED"))) {
|
||||
case "0", "false", "no", "off":
|
||||
enabled = false
|
||||
}
|
||||
c := &dnsRunCooldown{
|
||||
enabled: enabled,
|
||||
minAttempts: envInt("RESOLVE_DNS_COOLDOWN_MIN_ATTEMPTS", 300),
|
||||
timeoutRatePct: envInt("RESOLVE_DNS_COOLDOWN_TIMEOUT_RATE_PCT", 70),
|
||||
failStreak: envInt("RESOLVE_DNS_COOLDOWN_FAIL_STREAK", 25),
|
||||
banSec: envInt("RESOLVE_DNS_COOLDOWN_BAN_SEC", 60),
|
||||
maxBanSec: envInt("RESOLVE_DNS_COOLDOWN_MAX_BAN_SEC", 300),
|
||||
temporaryAsError: true,
|
||||
byUpstream: map[string]*dnsCooldownState{},
|
||||
}
|
||||
if c.minAttempts < 50 {
|
||||
c.minAttempts = 50
|
||||
}
|
||||
if c.minAttempts > 2000 {
|
||||
c.minAttempts = 2000
|
||||
}
|
||||
if c.timeoutRatePct < 40 {
|
||||
c.timeoutRatePct = 40
|
||||
}
|
||||
if c.timeoutRatePct > 95 {
|
||||
c.timeoutRatePct = 95
|
||||
}
|
||||
if c.failStreak < 8 {
|
||||
c.failStreak = 8
|
||||
}
|
||||
if c.failStreak > 200 {
|
||||
c.failStreak = 200
|
||||
}
|
||||
if c.banSec < 10 {
|
||||
c.banSec = 10
|
||||
}
|
||||
if c.banSec > 3600 {
|
||||
c.banSec = 3600
|
||||
}
|
||||
if c.maxBanSec < c.banSec {
|
||||
c.maxBanSec = c.banSec
|
||||
}
|
||||
if c.maxBanSec > 3600 {
|
||||
c.maxBanSec = 3600
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *dnsRunCooldown) configSnapshot() (enabled bool, minAttempts, timeoutRatePct, failStreak, banSec, maxBanSec int) {
|
||||
if c == nil {
|
||||
return false, 0, 0, 0, 0, 0
|
||||
}
|
||||
return c.enabled, c.minAttempts, c.timeoutRatePct, c.failStreak, c.banSec, c.maxBanSec
|
||||
}
|
||||
|
||||
func (c *dnsRunCooldown) stateFor(upstream string) *dnsCooldownState {
|
||||
if c.byUpstream == nil {
|
||||
c.byUpstream = map[string]*dnsCooldownState{}
|
||||
}
|
||||
st, ok := c.byUpstream[upstream]
|
||||
if ok {
|
||||
return st
|
||||
}
|
||||
st = &dnsCooldownState{}
|
||||
c.byUpstream[upstream] = st
|
||||
return st
|
||||
}
|
||||
|
||||
func (c *dnsRunCooldown) shouldSkip(upstream string, now int64) bool {
|
||||
if c == nil || !c.enabled {
|
||||
return false
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
st := c.stateFor(upstream)
|
||||
return st.BanUntil > now
|
||||
}
|
||||
|
||||
func (c *dnsRunCooldown) observeSuccess(upstream string) {
|
||||
if c == nil || !c.enabled {
|
||||
return
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
st := c.stateFor(upstream)
|
||||
st.Attempts++
|
||||
st.FailStreak = 0
|
||||
}
|
||||
|
||||
func (c *dnsRunCooldown) observeError(upstream string, kind dnsErrorKind, now int64) (bool, int) {
|
||||
if c == nil || !c.enabled {
|
||||
return false, 0
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
st := c.stateFor(upstream)
|
||||
st.Attempts++
|
||||
|
||||
timeoutLike := kind == dnsErrorTimeout || (c.temporaryAsError && kind == dnsErrorTemporary)
|
||||
if timeoutLike {
|
||||
st.TimeoutLike++
|
||||
st.FailStreak++
|
||||
} else {
|
||||
st.FailStreak = 0
|
||||
return false, 0
|
||||
}
|
||||
if st.BanUntil > now {
|
||||
return false, 0
|
||||
}
|
||||
|
||||
rateBan := st.Attempts >= c.minAttempts && (st.TimeoutLike*100 >= c.timeoutRatePct*st.Attempts)
|
||||
streakBan := st.FailStreak >= c.failStreak
|
||||
if !rateBan && !streakBan {
|
||||
return false, 0
|
||||
}
|
||||
|
||||
st.BanLevel++
|
||||
dur := c.banSec
|
||||
if st.BanLevel > 1 {
|
||||
for i := 1; i < st.BanLevel; i++ {
|
||||
dur *= 2
|
||||
if dur >= c.maxBanSec {
|
||||
dur = c.maxBanSec
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if dur > c.maxBanSec {
|
||||
dur = c.maxBanSec
|
||||
}
|
||||
st.BanUntil = now + int64(dur)
|
||||
st.FailStreak = 0
|
||||
return true, dur
|
||||
}
|
||||
Reference in New Issue
Block a user