Files
smallwebwaf/internal/servewaf/countries.go
T
sneak 230db01127
check / check (push) Waiting to run
servewaf: each decision heuristic is its own module (closes #195)
Each check servewaf runs on a request is a type in its own file behind
one interface, heuristic, and is registered in one of four ordered lists
in heuristics.go. Order and behaviour are unchanged.

Every refusal now logs heuristic, the name of the heuristic that made
it, and heuristic_figures, the figures it acted on. A ban by
refusal_limit or byte_limits after the answer logs after_answer_heuristic
and after_answer_heuristic_figures instead, so a line can name both. All
four are in docs/request-log.md, and SPEC.md names each heuristic at its
step.

Model: opus-5-5
2026-11-06 20:16:47 +00:00

43 lines
1.1 KiB
Go

package servewaf
// The heuristic countries. It reads SWWAF_DENIED_COUNTRIES and
// SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES.
import (
"context"
"slices"
"time"
"sneak.berlin/go/smallwebwaf/internal/requestlog"
)
// countries refuses a request by the client's country as it was looked up. A
// client without a country, or whose country cannot be found, is refused only
// by SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES. Its figures are the country and the
// setting that refused it.
type countries struct{}
func (countries) name() string { return "countries" }
func (countries) check(_ context.Context, rq *request, _ time.Time) *verdict {
denied := rq.h.config.DeniedCountries
allowed := rq.h.config.ExclusivelyAllowedCountries
country := rq.line.Country
var setting string
switch {
case slices.Contains(denied, country):
setting = "SWWAF_DENIED_COUNTRIES"
case len(allowed) > 0 && !slices.Contains(allowed, country):
setting = "SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES"
default:
return nil
}
return &verdict{
action: requestlog.ActionCountryDenied,
figures: map[string]any{"country": country, "setting": setting},
}
}