Files
smallwebwaf/internal/proxy/reputation.go
T
clawbot 0b2ff56417
check / check (push) Waiting to run
Blocklists and an AS percentage file fetched by URL (closes #29)
SWWAF_BLOCKLIST_URLS names lists of addresses and netblocks, fetched every
SWWAF_BLOCKLIST_REFRESH (24h, never under 1h). The last good copy is kept
whole in reputation.json and used while a fetch fails and across restarts.
SWWAF_BLOCKLIST_ACTION denies, limits or only logs a listed client; the log
line names the lists, each raises reputation_hit, and a failed fetch raises
source_failure. SWWAF_ASN_LIMIT_PERCENT_URL is fetched the same way and
counts as SWWAF_ASN_LIMIT_PERCENT does, the lower winning.

Judgement call: a restart fetches only lists whose copy is due.
Judgement call: a failed fetch is retried after the refresh, not sooner.
Not done: ban notes do not name the lists yet.

Model: opus-5-5
2026-10-07 15:10:41 +00:00

33 lines
1023 B
Go

package proxy
import (
"sneak.berlin/go/smallwebwaf/internal/alerts"
)
// blocklistDenied notes in the log line the URLs of the blocklists that
// list the client, counts each of them in the metrics and raises a
// reputation_hit alert for it, and reports whether SWWAF_BLOCKLIST_ACTION,
// being deny, refuses the request. Being limit, it lowers the client's
// limits instead (see limitPercentages), and being log, it does nothing
// more.
func (rq *request) blocklistDenied() bool {
listedBy := rq.h.lists.ListedBy(rq.client)
rq.line.Reputation = listedBy
for _, listURL := range listedBy {
rq.h.metrics.ReputationHit(listURL)
rq.h.alerts.Raise(alerts.Alert{
Event: alerts.EventReputationHit,
Client: rq.client,
Netblock: clientGroup(rq.client),
ASN: rq.line.ASN,
ASName: rq.line.ASName,
Country: rq.line.Country,
Reason: "listed by a blocklist",
Detail: map[string]any{"source": listURL},
})
}
return len(listedBy) > 0 && rq.h.config.BlocklistAction == "deny"
}