1 Commits
Author SHA1 Message Date
sneak 7fbe89469d Name request log actions so they say what they mean (closes #229)
check / check (push) Failing after 17m1s
Rename too_large, rate_limited, rule_blocked and denied, and split banned
into temporarily_banned and permanently_banned by whether the ban runs out.
A request that makes a ban permanent gets permanently_banned. A ban rule, a
trap path or a CrowdSec decision gets the value for the ban it makes, and in
observe mode would_action names the ban enforce mode would have made.

The offence kind rule_blocked follows, as a metric label and a key in
clients.json.

Model: opus-5-5
2026-11-09 04:05:44 +00:00
5 changed files with 36 additions and 12 deletions

No files matched your search

+2 -2
View File
@@ -100,8 +100,8 @@ Every one of these lines has:
the action `deny`, or for a tag in `SWW_TAG_DENY`;
- `temporarily_banned`: refused under a ban that runs out, or for a `ban`
rule, a trap path or a CrowdSec decision that made such a ban;
- `permanently_banned`: refused under a ban that never runs out, or for a
request that made such a ban or made its client's ban permanent;
- `permanently_banned`: refused under a ban that never runs out, including a
ban this request made or made permanent;
- `country_denied`, `client_is_rate_limited`, `blocked_by_block_rule` and
`waf_blocked`: refused by that check;
- `request_header_too_large`: over a header limit;
+4 -6
View File
@@ -100,8 +100,8 @@ func (rq *request) countedBytes() int64 {
// rate limit or a byte limit; the error burst is not lowered. The ban sets
// the client's counters back to zero. In observe mode it makes no ban and
// sets nothing back, and raises the alert for the ban it would have made,
// if that alert would be sent. It returns the action for that ban.
func (rq *request) banForLimit(now time.Time, hit ratelimit.Hit, status int) string {
// if that alert would be sent.
func (rq *request) banForLimit(now time.Time, hit ratelimit.Hit, status int) {
switch hit.Kind {
case ratelimit.KindBytes:
rq.line.LimitHit = hit.Window + "_bytes" // as counts names the byte totals
@@ -116,7 +116,7 @@ func (rq *request) banForLimit(now time.Time, hit ratelimit.Hit, status int) str
netblock := rq.h.netblock(rq.client)
if rq.h.config.Observe && !rq.wouldAlertBan(netblock, now, bans.CauseLimit) {
return banAction(rq.h.ledger.WouldBePermanent(netblock, now, bans.CauseLimit))
return
}
notes := bans.Notes{
@@ -145,7 +145,7 @@ func (rq *request) banForLimit(now time.Time, hit ratelimit.Hit, status int) str
rq.alertBan(ban)
}
return banAction(ban.Permanent())
return
}
ban, made := rq.h.ledger.BanForLimit(netblock, now, notes)
@@ -155,8 +155,6 @@ func (rq *request) banForLimit(now time.Time, hit ratelimit.Hit, status int) str
if made {
rq.alertBan(ban)
}
return banAction(ban.Permanent())
}
// banForAttack bans the client's netblock at now for a clear sign of
+3 -3
View File
@@ -35,7 +35,7 @@ func (byteLimits) check(_ context.Context, rq *request, now time.Time) *verdict
return nil
}
return &verdict{
action: rq.banForLimit(now, hit, rq.out.status), figures: limitFigures(hit),
}
rq.banForLimit(now, hit, rq.out.status)
return &verdict{figures: limitFigures(hit)}
}
+24
View File
@@ -7,6 +7,7 @@ import (
"testing"
"time"
"sneak.berlin/go/smallwebwaf/internal/alerts"
"sneak.berlin/go/smallwebwaf/internal/bans"
"sneak.berlin/go/smallwebwaf/internal/requestlog"
)
@@ -78,6 +79,29 @@ func TestBanActionSaysWhetherTheBanRunsOut(t *testing.T) {
}
}
func TestObserveModeNamesAPermanentBanWhoseAlertWouldBeSent(t *testing.T) {
t.Parallel()
s, clk, server, queue := startWithAlerts(t, map[string]string{
trapPaths: trapPathList, mode: observe,
})
server.Ledger.Load([]bans.Ban{{
Netblock: netip.MustParsePrefix(client + "/32"),
Start: clk.Now().Add(-2 * time.Hour),
Expires: clk.Now().Add(-time.Hour),
Cause: bans.CauseAttack,
}})
line := s.request(client, "/wp-login.php", http.StatusOK, requestlog.ActionForward)
wantWouldAction(t, line, requestlog.ActionPermanentlyBanned)
waiting := queue.Snapshot().Waiting[alerts.DestinationWebhook]
if len(waiting) != 1 || waiting[0].Event != alerts.EventPermanentBan {
t.Errorf("alerts waiting are %+v, want one %s", waiting, alerts.EventPermanentBan)
}
}
func TestObserveModeNamesTheHeuristicThatWouldHaveRefused(t *testing.T) {
t.Parallel()
+3 -1
View File
@@ -48,5 +48,7 @@ func (refusalLimit) check(_ context.Context, rq *request, now time.Time) *verdic
status = cfg.BanResponse
}
return &verdict{action: rq.banForLimit(now, hit, status), figures: limitFigures(hit)}
rq.banForLimit(now, hit, status)
return &verdict{figures: limitFigures(hit)}
}