check / check (push) Waiting to run
docs/core-rule-set.md, docs/lookup.md, docs/reputation.md and docs/bans.md restated the spec and are folded back into it and removed. The remaining docs files hold only lists: settings with their defaults and value forms, the request log's fields, the metrics, the endpoints, the state files and their contents, the rule file format and default file, the alert events and messages, the image's contents and pins, and the gitea notes. Every behaviour each of them held moves to the spec, said once. The settings groups have the same names in both files. Stale comments in internal/state and script/example-app point at the right places. Model: fable-5-1
109 lines
5.5 KiB
Markdown
109 lines
5.5 KiB
Markdown
# The request log's fields
|
|
|
|
The fields of the JSON object `smallwebwaf` writes for each request. "Request
|
|
log" in [`SPEC.md`](../SPEC.md) says when a line is written and how the log is
|
|
sent to a syslog server. A field that does not apply to a request is left out.
|
|
|
|
## Example
|
|
|
|
```
|
|
{"type":"request","time":"2026-10-03T12:00:00.123Z","instance":"fsn1app1/gitea","client_ip":"203.0.113.9","method":"GET","scheme":"https","host":"app.example","path":"/","query":"","protocol":"HTTP/1.1","status":200,"request_bytes":0,"response_bytes":5120,"referer":"","user_agent":"curl/8.9.1","request_id":"7Q2NHZ4KJ3VXW5YB6R3MEFTD2A","peer_ip":"172.18.0.2","forwarded_for":"203.0.113.9","client_group":"203.0.113.9/32","asn":"AS64496","as_name":"Example Net","country":"DE","request_headers":{"accept":"*/*"},"response_content_type":"text/html; charset=utf-8","upstream_status":200,"action":"forward","counts":{"minute":1,"hour":12,"day":40,"minute_bytes":5120,"hour_bytes":61440,"day_bytes":204800},"duration_total":3.217,"duration_checks":0.041,"duration_upstream_connect":0.052,"duration_upstream_first_byte":2.874,"duration_upstream_total":3.104}
|
|
```
|
|
|
|
## Every line
|
|
|
|
Every line has `type` (`request`; the process's own messages have `process`),
|
|
the standard web log fields, `request_id`, `peer_ip`, `client_group`, `asn`,
|
|
`as_name`, `country`, `action` and `duration_total`.
|
|
|
|
## Standard web log fields
|
|
|
|
- `time`: when the request arrived, RFC 3339 with milliseconds, in UTC;
|
|
- `instance`: `SWWAF_INSTANCE_NAME`;
|
|
- `client_ip`, `method`, `scheme`, `host`, `path`, `query`, `protocol`;
|
|
- `status`: what the client was sent, `0` if nothing;
|
|
- `request_bytes` and `response_bytes`: body bytes each way;
|
|
- `referer` and `user_agent`.
|
|
|
|
## Request detail
|
|
|
|
- `request_id`: the `X-Request-ID` a trusted proxy sent, or a new random one of
|
|
26 letters and digits. It goes to the app in `X-Request-ID`.
|
|
- `peer_ip`: the TCP peer, normally traefik.
|
|
- `forwarded_for`: the `X-Forwarded-For` header as received.
|
|
- `client_group`: the client as rate limiting counts it, an IPv4 address as a
|
|
/32 or an IPv6 group.
|
|
- `asn`, `as_name` and `country`: the client's, as looked up. Each is empty
|
|
when:
|
|
- lookups are off;
|
|
- the client is not looked up;
|
|
- the source cannot place the client;
|
|
- GeoJS had not answered by the time the request went on.
|
|
- `content_type` and `content_length`: the request's own.
|
|
- `request_headers`: the headers listed in `SWWAF_LOG_REQUEST_HEADERS`, by name
|
|
in lower case.
|
|
- `has_authorization` and `has_cookie`: true when the request had those headers.
|
|
Their values are never logged.
|
|
- `websocket`: true when the app switched the connection to another protocol.
|
|
|
|
## Response detail
|
|
|
|
- `upstream_status`: what the app answered. It differs from `status` when
|
|
`smallwebwaf` answered itself.
|
|
- `response_content_type`, `cache_control` and `location`: the answer's headers.
|
|
- `aborted`: true when the client went away early.
|
|
|
|
## Decision
|
|
|
|
- `action`: what was done:
|
|
- `forward`: passed to the app;
|
|
- `denied`: refused for `SWWAF_DENY_NETS`, or for a reputation source with
|
|
the action `deny`;
|
|
- `banned`: refused under a ban, or for a `ban` rule, a trap path or a
|
|
CrowdSec decision, each of which bans the client;
|
|
- `country_denied`, `rate_limited`, `rule_blocked` and `waf_blocked`:
|
|
refused by that check;
|
|
- `too_large` and `timed_out`: a size or time limit was passed;
|
|
- `upstream_error`: the app could not be reached, or its answer broke off;
|
|
- `admin`: answered at one of `smallwebwaf`'s own endpoints.
|
|
- `would_action`: in `observe` mode, what `enforce` mode would have done with a
|
|
request it would have refused. `action` then names what was done, normally
|
|
`forward`.
|
|
- `limit_percent` and `limit_percent_setting`: the client's percentage of the
|
|
rate limits and the setting that lowered it, when one did. `bytes_percent` and
|
|
`bytes_percent_setting` do the same for the byte limits.
|
|
- `counts`: the client's totals as rate limiting counts them, this request
|
|
included. It is left out when rate limiting did not count the request. A count
|
|
can have a fraction, since each window is counted in two buckets with the
|
|
earlier one weighted:
|
|
- `minute`, `hour` and `day`: requests;
|
|
- `minute_bytes`, `hour_bytes` and `day_bytes`: bytes.
|
|
- `limit_hit`: the limit broken: `minute`, `hour` or `day` for a rate limit;
|
|
`minute_bytes`, `hour_bytes` or `day_bytes` for a byte limit; or
|
|
`error_burst`. A request whose bytes broke a limit was passed on whole, so its
|
|
`action` stays `forward`.
|
|
- `rule_ids`: the rule file rules that matched, in order, up to the one that
|
|
refused.
|
|
- `waf_score` and `waf_rule_ids`: the Core Rule Set's score and the rules that
|
|
matched, for a request it inspected.
|
|
- `reputation`: the sources the client is on, in this order:
|
|
- blocklist URLs;
|
|
- the CrowdSec decision list's URL;
|
|
- DNS blocklist zones;
|
|
- `abuseipdb`.
|
|
- `offence`: the kind of offence recorded, when one was.
|
|
- `ban_expires`: when the client's ban ends, for a request that made one or was
|
|
refused under one: a time, or `permanent`.
|
|
|
|
## Timings
|
|
|
|
All in milliseconds:
|
|
|
|
- `duration_total`: from the request's headers being read to its log line;
|
|
- `duration_checks`: to the end of the checks, before forwarding;
|
|
- `duration_waf`: the part of that the Core Rule Set took;
|
|
- `duration_upstream_connect`: from the hand-over to the app until there was a
|
|
connection;
|
|
- `duration_upstream_first_byte`: until the first byte of the answer;
|
|
- `duration_upstream_total`: until the end of the answer.
|