Rules file
Every key a vulnboxd-rules.yml can hold. For explanations and examples, see Rules.
yaml
end_of_tick: allow # service-wide settings, overridable per port
intercept: true
pool_upstream: true
rules: [] # rules for every port whose protocol they fit
bypass: {} # {header: exact value}: http requests with all of them skip every rule
ports:
"8080": # published port; "53/udp" for udp
protocol: http # tcp | http | ftp on tcp ports, udp | dns on udp ports
end_of_tick: allow
intercept: true
pool_upstream: true
rules: []File and port settings
| key | where | default | |
|---|---|---|---|
end_of_tick | file, port | allow | what happens to new connections and datagrams in the end-of-tick window: allow lets them through, drop refuses them, stall holds them open until timeouts.stall |
intercept | file, port | true | false leaves the port exposed as it is, with no proxy and no rules; applied at the next deploy |
pool_upstream | file, port | true | reuse connections to the service between clients (http only) |
rules | file, port | [] | the rules, evaluated in order: service-wide first, then the port's |
bypass | file | {} | {header: value}; http requests carrying all of them, with exactly these values, skip every rule, and the headers are removed before the service sees them. Values need at least 12 characters |
ports | file | {} | per-port settings, keyed by "<port>" or "<port>/udp" |
protocol | port | tcp / udp | how the port's traffic is parsed |
Rule keys
| key | default | |
|---|---|---|
name | #<position> | shown in logs and metrics |
dir | in | in (to the service), out (to the client) or both |
match | always | conditions that must all hold |
not | never | skip the rule when all of these hold; head conditions only |
action | see below | block, stall, replace or log |
replace | {regex: replacement}, applied to the payload (http: the body) | |
set_status | 403 | http: status of the answer to a blocked message, or the new status of a response |
set_body | http: body of the answer to a blocked message, or the new body | |
set_headers | http: headers of the answer to a blocked message, or headers to set | |
remove_headers | http: header names to remove; case-insensitive, may end in * | |
keep_headers | http: header names to keep, removing the rest; Host and framing headers always stay | |
route | http: send matching requests here instead; host:port or a bare port | |
mirror | http: also send a copy here and log when the answers differ |
action defaults to replace if the rule has replace, remove_headers or keep_headers, and to block otherwise. stall answers nothing and holds the connection; it is for tcp, http and ftp ports, and cannot be combined with anything that changes the message.
Conditions
For match, and for not where marked.
| key | protocols | in not | |
|---|---|---|---|
contains | all | the payload contains this text | |
regex | all | the payload matches | |
method | http | ✓ | regex over the method; WEBSOCKET for websocket messages |
path | http | ✓ | regex over path and query |
headers | http | ✓ | {name: regex}; the header must be present |
headers_opt | http | ✓ | {name: regex}; a missing header also passes |
body | http | regex over the body alone; needs the whole body | |
status | http | ✓ | response status code |
qname | dns | ✓ | regex over the lower-cased query name |
qtype | dns | ✓ | query type, such as A or TXT |
larger_than | all | size in bytes, with K, M or G | |
distinct | all | {pattern: regex, over: n}: more than n different matches on one connection |
route and mirror rules can only use method, path, headers and headers_opt, since they are decided before the body is read.
Replacements
A replacement is either text or a transformation:
yaml
replace:
'password=\S+': 'password=***' # text; $1, ${name}, $$ for a literal $
'FLAG\{(\w+)\}': { encrypt: flags } # encrypt group 1 with key "flags"
'flag_([0-9a-f]{32})': { decrypt: hex, alphabet: 0123456789abcdef }See Encrypted flags.