Read SWWAF_IPV6_GROUP_PREFIX, SWWAF_MAX_TRACKED_CLIENTS and SWWAF_LOG_LEVEL (closes #112)
check / check (push) Waiting to run
check / check (push) Waiting to run
The IPv6 group that is one client, the size of the table of clients and the level of the process's own lines become settings. clientGroup reads the group length from them, so limits, bans, history, lookups, AbuseIPDB scores and per-client anomaly counters all follow it; ratelimit.New takes the table size; the process logger takes the level once the settings are read, and request lines, written apart from it, are never held back. Judgement call: SWWAF_IPV6_GROUP_PREFIX accepts 32 to 128, the issue's example range. Model: opus-5-5
This commit is contained in:
@@ -12,6 +12,10 @@ import (
|
||||
// limit is the limit the tests set.
|
||||
const limit = 3
|
||||
|
||||
// tableSize is the most clients the tests' tables hold, the default of
|
||||
// SWWAF_MAX_TRACKED_CLIENTS.
|
||||
const tableSize = 20000
|
||||
|
||||
// whole is the percentage of each limit a client gets when nothing lowers
|
||||
// its limits.
|
||||
const whole = 100
|
||||
@@ -37,7 +41,7 @@ func TestEachWindowRefusesAtItsLimitAndLetsTheClientBack(t *testing.T) {
|
||||
t.Run(tc.window, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(tc.limits)
|
||||
limiter := ratelimit.New(tc.limits, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
quarter := tc.length / 4
|
||||
@@ -62,7 +66,7 @@ func TestEachWindowRefusesAtItsLimitAndLetsTheClientBack(t *testing.T) {
|
||||
func TestHitGivesTheLimitAndTheRequestsCounted(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit, PerHour: limit})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit, PerHour: limit}, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -88,7 +92,8 @@ func TestHitGivesTheLimitAndTheRequestsCounted(t *testing.T) {
|
||||
func TestClientGetsItsPercentageOfEachLimitRoundedDown(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: 5, BytesPerDay: math.MaxInt64})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: 5, BytesPerDay: math.MaxInt64},
|
||||
tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -119,7 +124,8 @@ func TestZeroPercentIsAZeroAllowanceAndALimitOffStaysOff(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Only the hour has limits: the minute's and the day's are off.
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerHour: limit, BytesPerHour: 1000})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerHour: limit, BytesPerHour: 1000},
|
||||
tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -156,7 +162,7 @@ func TestEachByteLimitIsBrokenByTheBytesCounted(t *testing.T) {
|
||||
t.Run(tc.window, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(tc.limits)
|
||||
limiter := ratelimit.New(tc.limits, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
|
||||
// 600 bytes are within the limit, 600 more over it.
|
||||
@@ -180,7 +186,8 @@ func TestEachByteLimitIsBrokenByTheBytesCounted(t *testing.T) {
|
||||
func TestALimitIsBrokenOnlyByWhatIsAddedToIt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: 2, BytesPerMinute: 1000})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: 2, BytesPerMinute: 1000},
|
||||
tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
other := netip.MustParsePrefix("203.0.113.10/32")
|
||||
start := midnight()
|
||||
@@ -204,7 +211,7 @@ func TestALimitIsBrokenOnlyByWhatIsAddedToIt(t *testing.T) {
|
||||
func TestCountGivesTheBytesInEachWindow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{})
|
||||
limiter := ratelimit.New(ratelimit.Limits{}, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -230,7 +237,7 @@ func TestCountGivesTheBytesInEachWindow(t *testing.T) {
|
||||
func TestResetSetsTheBytesBackToZero(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{BytesPerDay: 1000})
|
||||
limiter := ratelimit.New(ratelimit.Limits{BytesPerDay: 1000}, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -244,7 +251,7 @@ func TestResetSetsTheBytesBackToZero(t *testing.T) {
|
||||
func TestCountGivesTheRequestsInEachWindow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{})
|
||||
limiter := ratelimit.New(ratelimit.Limits{}, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -267,7 +274,7 @@ func TestCountGivesTheRequestsInEachWindow(t *testing.T) {
|
||||
func TestResetSetsTheCountsBackToZero(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit, PerDay: limit})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit, PerDay: limit}, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -289,7 +296,7 @@ func TestResetSetsTheCountsBackToZero(t *testing.T) {
|
||||
func TestClientBackAfterAWholeBucketIsWithinTheLimitAtOnce(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerHour: limit})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerHour: limit}, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -308,7 +315,8 @@ func TestClientBackAfterAWholeBucketIsWithinTheLimitAtOnce(t *testing.T) {
|
||||
func TestRefusedRequestsCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit, PerHour: 2 * limit})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit, PerHour: 2 * limit},
|
||||
tableSize)
|
||||
refused := netip.MustParsePrefix("203.0.113.9/32")
|
||||
within := netip.MustParsePrefix("203.0.113.10/32")
|
||||
start := midnight()
|
||||
@@ -341,7 +349,7 @@ func TestRefusedRequestsCount(t *testing.T) {
|
||||
func TestRequestCountedLateGoesInTheBucketUnderWay(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit}, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -357,7 +365,7 @@ func TestRequestCountedLateGoesInTheBucketUnderWay(t *testing.T) {
|
||||
func TestClockSetBackStartsTheBucketsAfresh(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerHour: limit})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerHour: limit}, tableSize)
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
@@ -380,12 +388,12 @@ func TestClockSetBackStartsTheBucketsAfresh(t *testing.T) {
|
||||
wantCount(t, limiter, client, setBack, hour)
|
||||
}
|
||||
|
||||
func TestKeepsAtMost20000ClientsDroppingTheLeastRecentlySeen(t *testing.T) {
|
||||
func TestKeepsAtMostMaxClientsDroppingTheLeastRecentlySeen(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const maxClients = 20000
|
||||
const maxClients = 3
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: 1})
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: 1}, maxClients)
|
||||
now := midnight()
|
||||
|
||||
clients := make([]netip.Prefix, maxClients+1)
|
||||
@@ -407,6 +415,11 @@ func TestKeepsAtMost20000ClientsDroppingTheLeastRecentlySeen(t *testing.T) {
|
||||
// One client more drops the least recently seen, the second, which
|
||||
// starts afresh, while the first is kept.
|
||||
wantCount(t, limiter, clients[maxClients], now, "")
|
||||
|
||||
if limiter.Len() != maxClients {
|
||||
t.Errorf("the table holds %d clients, want %d", limiter.Len(), maxClients)
|
||||
}
|
||||
|
||||
wantCount(t, limiter, clients[1], now, "")
|
||||
wantCount(t, limiter, clients[0], now, minute)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user