{ "nftables": [ OBJECTS ] }
OBJECTS := LIST_OBJECTS | CMD_OBJECTS
LIST_OBJECTS := LIST_OBJECT [ , LIST_OBJECTS ]
CMD_OBJECTS := CMD_OBJECT [ , CMD_OBJECTS ]
CMD_OBJECT := { CMD: LIST_OBJECT } | METAINFO_OBJECT
CMD := "add" | "replace" | "create" | "insert" | "delete" | "list" | "reset" | "flush" | "rename"
LIST_OBJECT := TABLE | CHAIN | RULE | SET | MAP | ELEMENT | FLOWTABLE | COUNTER | QUOTA | CT_HELPER | LIMIT | METAINFO_OBJECT | CT_TIMEOUT | CT_EXPECTATION
libnftables supports JSON formatted input and output. This is implemented as an alternative frontend to the standard CLI syntax parser, therefore basic behaviour is identical and, for (almost) any operation available in standard syntax, there should be an equivalent one in JSON.
JSON input may be provided in a single string as parameter to nft_run_cmd_from_buffer() or in a file identified by the filename parameter of the nft_run_cmd_from_filename() function.
JSON output has to be enabled via the nft_ctx_output_set_json() function, turning library standard output into JSON format. Error output remains unaffected.
In general, any JSON input or output is enclosed in an object with a single property named nftables. Its value is an array containing commands (for input) or ruleset elements (for output).
A command is an object with a single property whose name identifies the command. Its value is a ruleset element - basically identical to output elements, apart from certain properties which may be interpreted differently or are required when output generally omits them.
In output, the first object in an nftables array is a special one containing library information. Its content is as follows:
{ "metainfo": { "version": STRING, "release_name": STRING, "json_schema_version": NUMBER }}
The values of version and release_name properties are equal to the package version and release name as printed by nft -v. The value of the json_schema_version property is an integer indicating the schema version.
If supplied in library input, the parser will verify the json_schema_version value to not exceed the internally hardcoded one (to make sure the given schema is fully understood). In future, a lower number than the internal one may activate compatibility mode to parse outdated and incompatible JSON input.
The structure accepts an arbitrary amount of commands which are interpreted in order of appearance. For instance, the following standard syntax input:
flush ruleset add table inet mytable add chain inet mytable mychain add rule inet mytable mychain tcp dport 22 accept
translates into JSON as such:
{ "nftables": [ { "flush": { "ruleset": null }}, { "add": { "table": { "family": "inet", "name": "mytable" }}}, { "add": { "chain": { "family": "inet", "table": "mytable", "chain": "mychain" }}} { "add": { "rule": { "family": "inet", "table": "mytable", "chain": "mychain", "expr": [ { "match": { "left": { "payload": { "protocol": "tcp", "field": "dport" }}, "right": 22 }}, { "accept": null } ] }}} ]}
{ "add": ADD_OBJECT } ADD_OBJECT := TABLE | CHAIN | RULE | SET | MAP | ELEMENT | FLOWTABLE | COUNTER | QUOTA | CT_HELPER | LIMIT | CT_TIMEOUT | CT_EXPECTATION
Add a new ruleset element to the kernel.
{ "replace": RULE }
Replace a rule. In RULE, the handle property is mandatory and identifies the rule to be replaced.
{ "create": ADD_OBJECT }
Identical to add command, but returns an error if the object already exists.
{ "insert": RULE }
This command is identical to add for rules, but instead of appending the rule to the chain by default, it inserts at first position. If a handle or index property is given, the rule is inserted before the rule identified by those properties.
{ "delete": ADD_OBJECT }
Delete an object from the ruleset. Only the minimal number of properties required to uniquely identify an object is generally needed in ADD_OBJECT. For most ruleset elements, this is family and table plus either handle or name (except rules since they don't have a name).
{ "list": LIST_OBJECT } LIST_OBJECT := TABLE | TABLES | CHAIN | CHAINS | SET | SETS | MAP | MAPS | COUNTER | COUNTERS | QUOTA | QUOTAS | CT_HELPER | CT_HELPERS | LIMIT | LIMITS | RULESET | METER | METERS | FLOWTABLE | FLOWTABLES | CT_TIMEOUT | CT_EXPECTATION
List ruleset elements. The plural forms are used to list all objects of that kind, optionally filtered by family and for some, also table.
{ "reset": RESET_OBJECT } RESET_OBJECT := COUNTER | COUNTERS | QUOTA | QUOTAS
Reset state in suitable objects, i.e. zero their internal counter.
{ "flush": FLUSH_OBJECT } FLUSH_OBJECT := TABLE | CHAIN | SET | MAP | METER | RULESET
Empty contents in given object, e.g. remove all chains from given table or remove all elements from given set.
{ "rename": CHAIN }
Rename a chain. The new name is expected in a dedicated property named newname.
{ "table": { "family": STRING, "name": STRING, "handle": NUMBER }}
This object describes a table.
family
name
handle
{ "chain": { "family": STRING, "table": STRING, "name": STRING, "newname": STRING, "handle": NUMBER, "type": STRING, "hook": STRING, "prio": NUMBER, "dev": STRING, "policy": STRING }}
This object describes a chain.
family
table
name
handle
newname
The following properties are required for base chains:
type
hook
prio
dev
policy
{ "rule": { "family": STRING, "table": STRING, "chain": STRING, "expr": [ STATEMENTS ], "handle": NUMBER, "index": NUMBER, "comment": STRING }} STATEMENTS := STATEMENT [, STATEMENTS ]
This object describes a rule. Basic building blocks of rules are statements. Each rule consists of at least one.
family
table
chain
expr
handle
index
comment
{ "set": { "family": STRING, "table": STRING, "name": STRING, "handle": NUMBER, "type": SET_TYPE, "policy": SET_POLICY, "flags": [ SET_FLAG_LIST ], "elem": SET_ELEMENTS, "timeout": NUMBER, "gc-interval": NUMBER, "size": NUMBER }} { "map": { "family": STRING, "table": STRING, "name": STRING, "handle": NUMBER, "type": SET_TYPE, "map": STRING, "policy": SET_POLICY, "flags": [ SET_FLAG_LIST ], "elem": SET_ELEMENTS, "timeout": NUMBER, "gc-interval": NUMBER, "size": NUMBER }} SET_TYPE := STRING | [ SET_TYPE_LIST ] SET_TYPE_LIST := STRING [, SET_TYPE_LIST ] SET_POLICY := "performance" | "memory" SET_FLAG_LIST := SET_FLAG [, SET_FLAG_LIST ] SET_FLAG := "constant" | "interval" | "timeout" SET_ELEMENTS := EXPRESSION | [ EXPRESSION_LIST ] EXPRESSION_LIST := EXPRESSION [, EXPRESSION_LIST ]
These objects describe a named set or map. Maps are a special form of sets in that they translate a unique key to a value.
family
table
name
handle
type
map
policy
flags
elem
timeout
gc-interval
size
The set type might be a string, such as "ipv4_addr" or an array consisting of strings (for concatenated types).
A single set element might be given as string, integer or boolean value for simple cases. If additional properties are required, a formal elem object may be used.
Multiple elements may be given in an array.
TYPE
{ "element": { "family": STRING, "table": STRING, "name": STRING, "elem": SET_ELEM }} SET_ELEM := EXPRESSION | [ EXPRESSION_LIST ] EXPRESSION_LIST := EXPRESSION [, EXPRESSION ]
Manipulate element(s) in a named set.
family
table
name
elem
{ "flowtable": { "family": STRING, "table": STRING, "name": STRING, "handle": NUMBER, "hook": STRING, "prio": NUMBER, "dev": FT_INTERFACE }} FT_INTERFACE := STRING | [ FT_INTERFACE_LIST ] FT_INTERFACE_LIST := STRING [, STRING ]
This object represents a named flowtable.
family
table
name
handle
hook
prio
dev
{ "counter": { "family": STRING, "table": STRING, "name": STRING, "handle": NUMBER, "packets": NUMBER, "bytes": NUMBER }}
This object represents a named counter.
family
table
name
handle
packets
bytes
{ "quota": { "family": STRING, "table": STRING, "name": STRING, "handle": NUMBER, "bytes": NUMBER, "used": NUMBER, "inv": BOOLEAN }}
This object represents a named quota.
family
table
name
handle
bytes
used
inv
{ "ct helper": { "family": STRING, "table": STRING, "name": STRING, "handle": ... ', "type": 'STRING, "protocol": CTH_PROTO, "l3proto": STRING }} CTH_PROTO := "tcp" | "udp"
This object represents a named conntrack helper.
family
table
name
handle
type
protocol
l3proto
{ "limit": { "family": STRING, "table": STRING, "name": STRING, "handle": NUMBER, "rate": NUMBER, "per": STRING, "burst": NUMBER, "unit": LIMIT_UNIT, "inv": BOOLEAN }} LIMIT_UNIT := "packets" | "bytes"
This object represents a named limit.
family
table
name
handle
rate
per
burst
unit
inv
{ "ct timeout": { "family": STRING, "table": STRING, "name": STRING, "handle": NUMBER, "protocol": CTH_PROTO, "state": STRING, "value: NUMBER, "l3proto": STRING }} CTH_PROTO := "tcp" | "udp" | "dccp" | "sctp" | "gre" | "icmpv6" | "icmp" | "generic"
This object represents a named conntrack timeout policy.
family
table
name
handle
protocol
state
value
l3proto
{ "ct expectation": { "family": STRING, "table": STRING, "name": STRING, "handle": NUMBER, "l3proto": STRING "protocol":* CTH_PROTO, "dport": NUMBER, "timeout: NUMBER, "size: NUMBER, *}} CTH_PROTO := "tcp" | "udp" | "dccp" | "sctp" | "gre" | "icmpv6" | "icmp" | "generic"
This object represents a named conntrack expectation.
family
table
name
handle
l3proto
protocol
dport
timeout
size
Statements are the building blocks for rules. Each rule consists of at least one.
{ "accept": null } { "drop": null } { "continue": null } { "return": null } { "jump": { "target": * STRING *}} { "goto": { "target": * STRING *}}
A verdict either terminates packet traversal through the current chain or delegates to a different one.
jump and goto statements expect a target chain name.
{ "match": { "left": EXPRESSION, "right": EXPRESSION, "op": STRING }}
This matches the expression on left hand side (typically a packet header or packet meta info) with the expression on right hand side (typically a constant value). If the statement evaluates to true, the next statement in this rule is considered. If not, processing continues with the next rule in the same chain.
left
right
op
OPERATORS
& |
Binary AND
|
| |
Binary OR
|
^ |
Binary XOR
|
<< |
Left shift
|
>> |
Right shift
|
== |
Equal
|
!= |
Not equal
|
< |
Less than
|
> |
Greater than
|
⇐ |
Less than or equal to
|
>= |
Greater than or equal to
|
in |
Perform a lookup, i.e. test if bits on RHS are contained in LHS value
|
Unlike with the standard API, the operator is mandatory here. In the standard API, a missing operator may be resolved in two ways, depending on the type of expression on the RHS:
For the non-trivial first case, the JSON API supports the in operator.
{ "counter": { "packets": NUMBER, "bytes": NUMBER }} { "counter": STRING }
This object represents a byte/packet counter. In input, no properties are required. If given, they act as initial values for the counter.
The first form creates an anonymous counter which lives in the rule it appears in. The second form specifies a reference to a named counter object.
packets
bytes
{ "mangle": { "key": EXPRESSION, "value": EXPRESSION }}
This changes the packet data or meta info.
key
value
{ "quota": { "val": NUMBER, "val_unit": STRING, "used": NUMBER, "used_unit": STRING, "inv": BOOLEAN }} { "quota": STRING }
The first form creates an anonymous quota which lives in the rule it appears in. The second form specifies a reference to a named quota object.
val
val_unit
used
used_unit
inv
{ "limit": { "rate": NUMBER, "rate_unit": STRING, "per": STRING, "burst": NUMBER, "burst_unit": STRING, "inv": BOOLEAN }} { "limit": STRING }
The first form creates an anonymous limit which lives in the rule it appears in. The second form specifies a reference to a named limit object.
rate
rate_unit
per
burst
burst_unit
inv
{ "fwd": { "dev": EXPRESSION, "family": FWD_FAMILY, "addr": EXPRESSION }} FWD_FAMILY := "ip" | "ip6"
Forward a packet to a different destination.
dev
family
addr
Both family and addr are optional, but if at least one is given, both must be present.
{ "notrack": null }
Disable connection tracking for the packet.
{ "dup": { "addr": EXPRESSION, "dev": EXPRESSION }}
Duplicate a packet to a different destination.
addr
dev
{ "snat": { "addr": EXPRESSION, "family": STRING, "port": EXPRESSION, "flags": FLAGS }} { "dnat": { "addr": EXPRESSION, "family": STRING, "port": EXPRESSION, "flags": FLAGS }} { "masquerade": { "port": EXPRESSION, "flags": FLAGS }} { "redirect": { "port": EXPRESSION, "flags": FLAGS }} FLAGS := FLAG | [ FLAG_LIST ] FLAG_LIST := FLAG [, FLAG_LIST ] FLAG := "random" | "fully-random" | "persistent"
Perform Network Address Translation.
addr
family
port
flags
All properties are optional and default to none.
{ "reject": { "type": STRING, "expr": EXPRESSION }}
Reject the packet and send the given error reply.
type
expr
{ "set": { "op": STRING, "elem": EXPRESSION, "set": STRING }}
Dynamically add/update elements to a set.
op
elem
set
{ "log": { "prefix": STRING, "group": NUMBER, "snaplen": NUMBER, "queue-threshold": NUMBER, "level": LEVEL, "flags": FLAGS }} LEVEL := "emerg" | "alert" | "crit" | "err" | "warn" | "notice" | "info" | "debug" | "audit" FLAGS := FLAG | [ FLAG_LIST ] FLAG_LIST := FLAG [, FLAG_LIST ] FLAG := "tcp sequence" | "tcp options" | "ip options" | "skuid" | "ether" | "all"
Log the packet.
prefix
group
snaplen
queue-threshold
level
flags
{ "ct helper": EXPRESSION }
Enable the specified conntrack helper for this packet.
ct helper
{ "meter": { "name": STRING, "key": EXPRESSION, "stmt": STATEMENT }}
Apply a given statement using a meter.
name
key
stmt
{ "queue": { "num": EXPRESSION, "flags": FLAGS }} FLAGS := FLAG | [ FLAG_LIST ] FLAG_LIST := FLAG [, FLAG_LIST ] FLAG := "bypass" | "fanout"
Queue the packet to userspace.
num
flags
{ "vmap": { "key": EXPRESSION, "data": EXPRESSION }}
Apply a verdict conditionally.
key
data
{ "ct count": { "val": NUMBER, "inv": BOOLEAN }}
Limit the number of connections using conntrack.
val
inv
{ "ct timeout": EXPRESSION }
Assign connection tracking timeout policy.
ct timeout
{ "ct expectation": EXPRESSION }
Assign connection tracking expectation.
ct expectation
{ "xt": null }
This represents an xt statement from xtables compat interface. Sadly, at this point, it is not possible to provide any further information about its content.
Expressions are the building blocks of (most) statements. In their most basic form, they are just immediate values represented as a JSON string, integer or boolean type.
STRING NUMBER BOOLEAN
Immediate expressions are typically used for constant values. For strings, there are two special cases:
@STRING
\*
ARRAY
List expressions are constructed by plain arrays containing of an arbitrary number of expressions.
{ "concat": CONCAT } CONCAT := [ EXPRESSION_LIST ] EXPRESSION_LIST := EXPRESSION [, EXPRESSION_LIST ]
Concatenate several expressions.
{ "set": SET } SET := EXPRESSION | [ EXPRESSION_LIST ]
This object constructs an anonymous set. For mappings, an array of arrays with exactly two elements is expected.
{ "map": { "key": EXPRESSION, "data": EXPRESSION }}
Map a key to a value.
key
data
{ "prefix": { "addr": EXPRESSION, "len": NUMBER }}
Construct an IPv4 or IPv6 prefix consisting of address part in addr and prefix length in len.
{ "range": [ EXPRESSION , EXPRESSION ] }
Construct a range of values. The first array item denotes the lower boundary, the second one the upper boundary.
{ "payload": { "base": BASE, "offset": NUMBER, "len": NUMBER }} { "payload": { "protocol": STRING, "field": STRING }} BASE := "ll" | "nh" | "th"
Construct a payload expression, i.e. a reference to a certain part of packet data. The first form creates a raw payload expression to point at a random number (len) of bytes at a certain offset (offset) from a given reference point (base). The following base values are accepted:
"ll"
"nh"
"th"
The second form allows to reference a field by name (field) in a named packet header (protocol).
{ "exthdr": { "name": STRING, "field": STRING, "offset": NUMBER }}
Create a reference to a field (field) in an IPv6 extension header (name). offset is used only for rt0 protocol.
If the field property is not given, the expression is to be used as a header existence check in a match statement with a boolean on the right hand side.
{ "tcp option": { "name": STRING, "field": STRING }}
Create a reference to a field (field) of a TCP option header (name).
If the field property is not given, the expression is to be used as a TCP option existence check in a match statement with a boolean on the right hand side.
{ "meta": { "key": META_KEY }} META_KEY := "length" | "protocol" | "priority" | "random" | "mark" | "iif" | "iifname" | "iiftype" | "oif" | "oifname" | "oiftype" | "skuid" | "skgid" | "nftrace" | "rtclassid" | "ibriport" | "obriport" | "ibridgename" | "obridgename" | "pkttype" | "cpu" | "iifgroup" | "oifgroup" | "cgroup" | "nfproto" | "l4proto" | "secpath"
Create a reference to packet meta data.
{ "rt": { "key": RT_KEY, "family": RT_FAMILY }} RT_KEY := "classid" | "nexthop" | "mtu" RT_FAMILY := "ip" | "ip6"
Create a reference to packet routing data.
The family property is optional and defaults to unspecified.
{ "ct": { "key": STRING, "family": CT_FAMILY, "dir": CT_DIRECTION }} CT_FAMILY := "ip" | "ip6" CT_DIRECTION := "original" | "reply"
Create a reference to packet conntrack data.
Some CT keys do not support a direction. In this case, dir must not be given.
{ "numgen": { "mode": NG_MODE, "mod": NUMBER, "offset": NUMBER }} NG_MODE := "inc" | "random"
Create a number generator.
The offset property is optional and defaults to 0.
{ "jhash": { "mod": NUMBER, "offset": NUMBER, "expr": EXPRESSION, "seed": NUMBER }} { "symhash": { "mod": NUMBER, "offset": NUMBER }}
Hash packet data.
The offset and seed properties are optional and default to 0.
{ "fib": { "result": FIB_RESULT, "flags": FIB_FLAGS }} FIB_RESULT := "oif" | "oifname" | "type" FIB_FLAGS := FIB_FLAG | [ FIB_FLAG_LIST ] FIB_FLAG_LIST := FIB_FLAG [, FIB_FLAG_LIST ] FIB_FLAG := "saddr" | "daddr" | "mark" | "iif" | "oif"
Perform kernel Forwarding Information Base lookups.
{ "|": [ EXPRESSION, EXPRESSION ] } { "^": [ EXPRESSION, EXPRESSION ] } { "&": [ EXPRESSION, EXPRESSION ] } { "<<": [ EXPRESSION, EXPRESSION ] } { ">>": [ EXPRESSION, EXPRESSION ] }
All binary operations expect an array of exactly two expressions, of which the first element denotes the left hand side and the second one the right hand side.
{ "accept": null } { "drop": null } { "continue": null } { "return": null } { "jump": { "target": STRING }} { "goto": { "target": STRING }}
Same as the verdict statement, but for use in verdict maps.
jump and goto verdicts expect a target chain name.
{ "elem": { "val": EXPRESSION, "timeout": NUMBER, "expires": NUMBER, "comment": STRING }}
Explicitly set element object, in case timeout, expires or comment are desired. Otherwise, it may be replaced by the value of val.
{ "socket": { "key": SOCKET_KEY }} SOCKET_KEY := "transparent"
Construct a reference to packet's socket.
{ "osf": { "key": OSF_KEY, "ttl": OSF_TTL }} OSF_KEY := "name" OSF_TTL := "loose" | "skip"
Perform OS fingerprinting. This expression is typically used in the LHS of a match statement.
key
ttl
Phil Sutter <phil@nwl.cc>