Skip to content

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 ​

keywheredefault
end_of_tickfile, portallowwhat 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
interceptfile, porttruefalse leaves the port exposed as it is, with no proxy and no rules; applied at the next deploy
pool_upstreamfile, porttruereuse connections to the service between clients (http only)
rulesfile, port[]the rules, evaluated in order: service-wide first, then the port's
bypassfile{}{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
portsfile{}per-port settings, keyed by "<port>" or "<port>/udp"
protocolporttcp / udphow the port's traffic is parsed

Rule keys ​

keydefault
name#<position>shown in logs and metrics
dirinin (to the service), out (to the client) or both
matchalwaysconditions that must all hold
notneverskip the rule when all of these hold; head conditions only
actionsee belowblock, stall, replace or log
replace{regex: replacement}, applied to the payload (http: the body)
set_status403http: status of the answer to a blocked message, or the new status of a response
set_bodyhttp: body of the answer to a blocked message, or the new body
set_headershttp: headers of the answer to a blocked message, or headers to set
remove_headershttp: header names to remove; case-insensitive, may end in *
keep_headershttp: header names to keep, removing the rest; Host and framing headers always stay
routehttp: send matching requests here instead; host:port or a bare port
mirrorhttp: 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.

keyprotocolsin not
containsallthe payload contains this text
regexallthe payload matches
methodhttp✓regex over the method; WEBSOCKET for websocket messages
pathhttp✓regex over path and query
headershttp✓{name: regex}; the header must be present
headers_opthttp✓{name: regex}; a missing header also passes
bodyhttpregex over the body alone; needs the whole body
statushttp✓response status code
qnamedns✓regex over the lower-cased query name
qtypedns✓query type, such as A or TXT
larger_thanallsize in bytes, with K, M or G
distinctall{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.