Commit Graph
4 Commits
Author SHA1 Message Date
clawbot 7f472c40e2 Rule files, and bans for a clear sign of attack (closes #24)
check / check (push) Waiting to run
Every *.rules file in SWWAF_RULES_DIR is read at start and on each
change, and each request is checked against the rules after the rate
limits: log notes a match, block refuses with 403, ban refuses and bans
the netblock for SWWAF_ATTACK_BAN_DURATION, made permanent by its next
request or clear sign of attack. path, query and uri are matched as the
request line sent them. bans.json gains each ban's cause, and ban notes
count earlier bans by cause. The image ships 00-default.rules.

Judgement call: a header sent twice is matched with its values joined
by ", ".
Judgement call: SWWAF_MAX_BAN_DURATION does not cap a ban for an attack.
Not in this unit: offences for rule matches, with the error burst.

Model: opus-5-5
2026-10-06 14:33:26 +00:00
clawbot cff385af41 Observe mode: log what would be refused, refuse nothing (closes #78)
check / check (push) Waiting to run
SWWAF_MODE (default enforce) takes enforce or observe. In observe mode a
request that SWWAF_DENY_NETS, a ban, the country lists or a rate limit
would refuse is passed to the app, and its log line names that refusal
in would_action. The size and time limits and the 401 still apply. A
broken limit makes no ban; bans read from bans.json are kept but refuse
nothing, and Ledger.Find reads them without counting a refusal in their
notes.

Judgement call: in observe mode a broken limit does not reset the
client's counters, since the reset comes with the ban.
Judgement call: a request a ban would refuse keeps ban_expires.

Model: opus-5-5
2026-10-06 13:04:43 +02:00
clawbot df2c5042d2 Keep the bans, the clients and GeoJS's answers in state files (closes #17)
check / check (push) Successful in 3m24s
smallwebwaf now copies its state to bans.json, clients.json and
lookups.json in SWWAF_STATE_DIR, as "Persistent state" in SPEC.md
describes, and reads them back at start, so a restart lifts no ban and
gives no client a fresh allowance. Each client gains a history, and a
ban's notes count the netblock's requests. bans.json is written
SWWAF_STATE_WRITE_DELAY after a ban, and every file every
SWWAF_STATE_COUNTER_INTERVAL and at the stop. A ban read back is masked
to its netblock and refuses every client in it. A file that does not
parse, an unknown version, an entry without a field it needs, or an
unwritable directory stops the start.

Deviation: no AS number or name, and no ban cause, reason or lifting yet.

Model: opus-5-5
2026-10-06 08:31:52 +02:00
clawbot 73ca94f850 Ban the netblock of a client that breaks a rate limit, in memory (closes #18)
check / check (push) Successful in 3m48s
A request over a rate limit is refused with SWWAF_BAN_RESPONSE and bans
the client's netblock: an hour at first, three times the last ban when
broken again within a day of its end, permanent past seven days. The
ban ledger in internal/bans is checked after the static lists and
before the lookup, and the requests it refuses are not counted. A ban
resets the client's counters and carries notes holding the request
that broke the limit, as SPEC.md now says. At most SWWAF_MAX_BANS are
held. SWWAF_BAN_RESPONSE also answers SWWAF_DENY_NETS and the country
lists.

Judgement call: the six ban settings cannot be off.
Judgement call: a permanent ban's ban_expires is "permanent".

Model: opus-5-5
2026-10-06 05:29:03 +02:00