servewaf answers rproxy's question about each request and takes its report (closes #170)
check / check (push) Successful in 4m27s

`smallwebwaf servewaf` runs today's checks on the visitor's request a
question carries and answers allow, deny or close, instead of passing it
to an app. rproxy's report then counts the bytes toward the byte limits
and adds the request to the client's history. SPEC.md gives the exact
question, answer and report, which rproxy follows. `smallwebwaf` with no
command is unchanged.

Judgement call: a third disposition, close, since closing the question's
connection would read as servewaf down and let the request through.
Judgement call: allow can answer a new request id, since a visitor behind
a trusted proxy can choose its own.

Model: opus-5-5
This commit is contained in:
2026-11-04 19:41:12 +00:00
parent fdabf4974b
commit ed6ba53747
25 changed files with 1673 additions and 85 deletions
+33
View File
@@ -117,3 +117,36 @@ All in milliseconds:
connection;
- `duration_upstream_first_byte`: until the first byte of the answer;
- `duration_upstream_total`: until the end of the answer.
## `servewaf`'s line
`smallwebwaf servewaf` writes one line for each question, once it has answered
it, and one for each request to its own endpoints but a report. A report writes
no line. A question's line has the fields above, with these meanings where they
differ:
- `client_ip`: `X-Smallwebwaf-Client`.
- `peer_ip`: `X-Smallwebwaf-Peer`.
- `host`: the site the visitor asked for.
- `protocol`: the question's own, `HTTP/1.1`.
- `content_length`: `X-Smallwebwaf-Content-Length`.
- `request_id`: the id `servewaf` answers with on `allow`.
- `status`: what `servewaf` answered: `200` for `allow`, the status of `deny`,
or `0` for `close`, as the visitor is then sent nothing.
- `request_bytes`: how much of the question's body the Core Rule Set read.
- `response_bytes`: the body of `servewaf`'s answer.
- `action`: `forward` for `allow`, and `admin` for the `404` for a path under
`/_smallwebwaf/`.
- `aborted`: true when `rproxy` went away before the answer.
- `duration_total`: from the question's headers being read to the line.
The line leaves out `upstream_status`, `websocket` and the
`duration_upstream_...` fields, since `servewaf` passes nothing to the app.
`rproxy` holds the visitor's status, the body bytes and the times of the app's
answer. The request id joins the two.
The bytes of an allowed request are counted when its report comes, after its
line. So `counts` holds the client's bytes without this request's. A report that
breaks a byte limit writes a process message instead of `limit_hit` on the line:
`a report's bytes broke a byte limit`, with `request_id`, `client_ip`, `host`,
`limit_hit` and `ban_expires`.