AbuseIPDB scores for clients that committed an offence, within a daily budget (closes #105)
check / check (push) Waiting to run
check / check (push) Waiting to run
With SWWAF_ABUSEIPDB_KEY set, a client whose history counts an offence (a broken limit, a ban rule's match or a block rule's refusal, counted by kind) is checked in the background, at most SWWAF_ABUSEIPDB_DAILY_BUDGET checks a day, the count kept in reputation.json. A client, an IPv4 address or an IPv6 /64, is checked by the address it sent from, and its score serves all its addresses. A score at or over SWWAF_ABUSEIPDB_MIN_SCORE is a hit for SWWAF_REPUTATION_ACTION, logged as abuseipdb and alerted with its score. A failure or the used-up budget gives no score and raises source_failure. The key goes only in the Key header. Judgement call: the budget's day is UTC; AbuseIPDB documents no reset time. Judgement call: each check sent spends budget; a minute's pause after a failure. Model: opus-5-5
This commit was merged in pull request #111.
This commit is contained in:
@@ -3,9 +3,10 @@
|
||||
// SWWAF_ASN_LIMIT_PERCENT_URL names. It keeps the last good copy of each,
|
||||
// whole, comment lines included, which is used while a fetch fails, and
|
||||
// when each was last tried. It also asks the DNSBL zones of
|
||||
// SWWAF_DNSBL_ZONES about clients, and keeps their verdicts. The state
|
||||
// package writes all of these to reputation.json and reads them from it,
|
||||
// so that a restart keeps them too.
|
||||
// SWWAF_DNSBL_ZONES about clients, and keeps their verdicts, and checks
|
||||
// clients with AbuseIPDB, and keeps their scores and the checks spent
|
||||
// today. The state package writes all of these to reputation.json and
|
||||
// reads them from it, so that a restart keeps them too.
|
||||
package reputation
|
||||
|
||||
import (
|
||||
@@ -329,11 +330,7 @@ func (l *Lists) fetch(ctx context.Context, listURL string) {
|
||||
|
||||
// Raised before it is logged, so that the alert is there once the
|
||||
// log line is.
|
||||
l.params.Alerts.Raise(alerts.Alert{
|
||||
Event: alerts.EventSourceFailure,
|
||||
Reason: failed,
|
||||
Detail: map[string]any{"source": listURL, "error": err.Error()},
|
||||
})
|
||||
raiseFailure(l.params.Alerts, failed, listURL, err)
|
||||
l.params.ProcessLog.Warn(failed, "url", listURL, "error", err.Error())
|
||||
|
||||
return
|
||||
@@ -342,6 +339,17 @@ func (l *Lists) fetch(ctx context.Context, listURL string) {
|
||||
l.params.ProcessLog.Info("fetched a list", "url", listURL, "lines", len(lines))
|
||||
}
|
||||
|
||||
// raiseFailure raises a source_failure alert into queue, with reason, and
|
||||
// in its detail the source that failed, a list's URL, a zone with its key
|
||||
// masked or abuseipdb, and err.
|
||||
func raiseFailure(queue *alerts.Queue, reason, source string, err error) {
|
||||
queue.Raise(alerts.Alert{
|
||||
Event: alerts.EventSourceFailure,
|
||||
Reason: reason,
|
||||
Detail: map[string]any{"source": source, "error": err.Error()},
|
||||
})
|
||||
}
|
||||
|
||||
// get fetches the list at listURL, and returns its lines. An answer other
|
||||
// than 200, or a list longer than maxListBytes, is a failure.
|
||||
func (l *Lists) get(ctx context.Context, listURL string) ([]string, error) {
|
||||
|
||||
Reference in New Issue
Block a user