1
0
mirror of https://github.com/HorlogeSkynet/Nftables synced 2024-11-24 20:00:11 +01:00
Nftables/Nftables.sublime-syntax

750 lines
25 KiB
YAML

%YAML 1.2
---
# nftables syntax definition for Sublime Text 3 (>= 3092).
# `file_extensions` contains `nftables.conf` to match the default packaged file in Debian.
# `first_line_match` should match (at least) this shebang `#!/usr/sbin/nft -f`.
name: Nftables
file_extensions: [nft, nftables, nftables.conf]
first_line_match: (?:^\#!\s*\/.*\bs?bin\b.*\bnft\b)
scope: source.nftables
hidden: false
variables:
integer: (?:[[:digit:]]+)
hexadecimal: (?:(?:0x)[[:xdigit:]]+)
time_string: (?:(?:\d+[wdhms])+)
identifier: (?:[[:alpha:]_][[:alnum:]_]*)
identifier_extended: (?:[[:alpha:]_][[:alnum:]_\-\.]*)
chain_types: (?:\b(filter|route|nat)\b)
chain_hooks: (?:\b(prerouting|input|forward|output|postrouting|ingress)\b)
family_types: (?:\b(arp|bridge|inet|ip6?|netdev)\b)
# From <https://stackoverflow.com/a/4260512>.
mac_address: |-
(?x)
(?:[0-9a-fA-F]{2}[:-]){5}(?:[0-9a-fA-F]{2})
# From <https://stackoverflow.com/a/17871737>.
ipv4_address: |-
(?x)
(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3}
(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])
ipv6_address: |-
(?x)
(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|
(?:[0-9a-fA-F]{1,4}:){1,7}:|
(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|
(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|
(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|
(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|
(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|
[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|
:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|
fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|
::(?:ffff(?::0{1,4}){0,1}:){0,1}
(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|
(?:[0-9a-fA-F]{1,4}:){1,4}:
(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}
(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])
# From <http://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses/>.
ipv4_subnet: |-
(?x)
(?:{{ipv4_address}})
(?:\/)
(?:3[0-2]|[1-2][0-9]|[0-9])
ipv6_subnet: |-
(?x)
(?:{{ipv6_address}})
(?:\/)
(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9])
contexts:
main:
- include: common-blocks
- include: specifications
- include: script-commands
prototype:
- include: comments
- include: variables
- include: line-continuation
comments:
- match: (#)
scope: punctuation.definition.comment.nftables
push:
- meta_scope: comment.line.nftables
- match: (?=$)
pop: true
variables:
- match: (\$)({{identifier}})
captures:
1: punctuation.definition.variable.nftables
2: variable.other.constant.nftables
- match: (@)({{identifier}})
captures:
1: punctuation.definition.variable.nftables
2: variable.other.readwrite.set.nftables
statement-separators:
# Elements matching below patterns will 'pop' the current context off the stack.
- match: (;)
scope: punctuation.terminator.semi-colon.nftables
pop: true
- match: ($\n)
pop: true
comma:
- match: (,)
scope: punctuation.separator.comma.nftables
colon:
- match: (:)
scope: punctuation.separator.colon.nftables
semi-colon:
- match: (;)
scope: punctuation.terminator.semi-colon.nftables
line-continuation:
- match: (?:(\\)(.*)$\n)
captures:
1: punctuation.separator.continuation.nftables
2: invalid.illegal.trailing-character.nftables
values:
- include: safe-values
- include: time-string
- include: unquoted-string
safe-values:
- include: quoted-string
- include: network-addresses
- include: numerics
- include: variables
- include: anonymous-set
quoted-string:
# Apparently nftables only supports double-quoted strings.
# `prototype` won't be propagated, but `line-continuation` has to be consumed.
- match: (")
scope: punctuation.definition.string.begin.nftables
with_prototype:
- match: (\\.)
scope: constant.character.escape.nftables
- include: line-continuation
push:
- meta_include_prototype: false
- meta_scope: string.quoted.double.nftables meta.string.nftables
- match: (")
scope: punctuation.definition.string.end.nftables
pop: true
time-string:
- match: \b({{time_string}})\b
scope: string.unquoted.time-string.nftables
_expect-time-string:
- match: \b({{time_string}})\b
scope: string.unquoted.time-string.nftables
pop: true
unquoted-string:
- match: \b({{identifier_extended}})\b
scope: string.unquoted.nftables
_expect-unquoted-string:
- match: \b({{identifier_extended}})\b
scope: string.unquoted.nftables
pop: true
network-addresses:
- match: ({{mac_address}})
scope: constant.numeric.mac-address.nftables
- match: ({{ipv4_subnet}})
scope: constant.numeric.ipv4-subnet.nftables
- match: ({{ipv4_address}})
scope: constant.numeric.ipv4-address.nftables
- match: ({{ipv6_subnet}})
scope: constant.numeric.ipv6-subnet.nftables
- match: ({{ipv6_address}})
scope: constant.numeric.ipv6-address.nftables
numerics:
- include: integers-range
- include: signed-integer
- include: hexadecimal
integers-range:
- match: ({{integer}})(\-)({{integer}})
captures:
1: constant.numeric.integer.nftables
2: punctuation.separator.dash.nftables
3: constant.numeric.integer.nftables
hexadecimal:
- match: \b({{hexadecimal}})\b
scope: constant.numeric.integer.hexadecimal.nftables
signed-integer:
- match: (\-)?\b{{integer}}\b
captures:
0: constant.numeric.integer.signed.nftables
1: keyword.operator.arithmetic.nftables
integer:
# This context is not included in `numerics` because `signed-integer` supersedes it.
- match: \b({{integer}})\b
scope: constant.numeric.integer.nftables
_expect-integer:
- match: \b({{integer}})\b
scope: constant.numeric.integer.nftables
pop: true
anonymous-set:
- match: ({)
scope: punctuation.section.braces.begin.anonymous-set.nftables
push:
- meta_scope: meta.object.anonymous-set.nftables
# Anonymous sets may contain values, operators and specific separators.
# Elements in the set may have a `timeout` (death-date).
- match: \b(timeout)\b
scope: storage.type.set-element-timeout.nftables
push: _expect-time-string
- include: verdict-statements
- include: values
- include: operators
- include: comma
- include: colon
- match: (})
scope: punctuation.section.braces.end.anonymous-set.nftables
pop: true
assignment:
- match: (=)
scope: keyword.operator.assignment.nftables
set:
- include: values
- include: statement-separators
common-blocks:
# Defines.
- match: \b(define|redefine)\b
scope: keyword.control.define.nftables
push:
- match: \b({{identifier}})\b
scope: variable.other.constant.nftables
set: assignment
- match: \b(undefine)\b
scope: keyword.control.undefine.nftables
push:
- match: \b({{identifier}})\b
scope: variable.other.constant.nftables
pop: true
# Include.
- match: \b(include)\b
scope: keyword.control.import.nftables
push:
- include: quoted-string
- include: statement-separators
- include: semi-colon
script-commands:
- match: |-
(?x)
\b(
add|replace|create|
insert|delete|
get|list|
reset|flush|
rename|
import|export|
monitor|describe|
remove
)\b
scope: keyword.other.command.nftables
push:
- match: \b(table)\b
scope: storage.type.table.nftables keyword.declaration.table.nftables
set:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: entity.name.table.nftables
set:
- match: ({)
scope: punctuation.section.block.begin.table.nftables
set:
- meta_scope: meta.block.table.nftables
- include: table-flags
- include: statement-separators
- match: (})
scope: punctuation.section.block.end.table.nftables
pop: true
- include: statement-separators
- match: \b(chain)\b
scope: storage.type.chain.nftables keyword.declaration.chain.nftables
set:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: chain-specs
- match: \b(flowtable)\b
scope: storage.type.flowtable.nftables keyword.declaration.flowtable.nftables
set:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: flowtable-specs
- match: \b(rule)\b
scope: storage.type.rule.nftables keyword.declaration.rule.nftables
set: rule-command
- match: \b(set|map)\b
scope: storage.type.set.nftables keyword.declaration.set.nftables
set:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: set-specs
- match: \b(element)\b
scope: storage.type.element.nftables keyword.declaration.element.nftables
set:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set:
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.set.nftables
set:
- include: anonymous-set
- include: statement-separators
- match: \b(quota)\b
scope: storage.type.quota.nftables keyword.declaration.quota.nftables
set:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: quota-specs
- match: (?:\bct\b\s+\b(helper)\b)
captures:
1: storage.type.helper.nftables keyword.declaration.helper.nftables
set: helper-specs
- match: \b(ruleset)\b
scope: keyword.other.ruleset.nftables
set:
- include: family-types
- include: statement-separators
- include: rule-command
- include: statement-separators
rule-command:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set:
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.chain.nftables
set:
- match: \b(handle|position)\b
scope: keyword.other.handle.nftables
push: _expect-integer
- include: rule-definitions
- include: statement-separators
# Some commands do not require to specify a chain, so we must allow it to end right here.
- include: statement-separators
specifications:
- include: table-specs
- match: \b(chain)\b
scope: storage.type.chain.nftables keyword.declaration.chain.nftables
push:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: chain-specs
- match: \b(flowtable)\b
scope: storage.type.flowtable.nftables keyword.declaration.flowtable.nftables
push:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: flowtable-specs
- match: \b(set|map)\b
scope: storage.type.set.nftables keyword.declaration.set.nftables
push:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: set-specs
- match: \b(quota)\b
scope: storage.type.quota.nftables keyword.declaration.quota.nftables
push:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: quota-specs
- match: (?:\bct\b\s+\b(helper)\b)
captures:
1: storage.type.helper.nftables keyword.declaration.helper.nftables
push:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.table.nftables
set: helper-specs
table-specs:
- match: \b(table)\b
scope: storage.type.table.nftables keyword.declaration.table.nftables
push:
- include: family-types
- match: \b({{identifier_extended}})\b
scope: entity.name.table.nftables
set:
- match: ({)
scope: punctuation.section.block.begin.table.nftables
set:
- meta_scope: meta.block.table.nftables
- include: table-flags
- include: common-blocks
- match: \b(chain)\b
scope: storage.type.chain.nftables keyword.declaration.chain.nftables
push: chain-specs
- match: \b(flowtable)\b
scope: storage.type.flowtable.nftables keyword.declaration.flowtable.nftables
push: flowtable-specs
- match: \b(set|map)\b
scope: storage.type.set.nftables keyword.declaration.set.nftables
push: set-specs
- match: \b(quota)\b
scope: storage.type.quota.nftables keyword.declaration.quota.nftables
push: quota-specs
- match: (?:\bct\b\s+\b(helper)\b)
captures:
1: storage.type.helper.nftables keyword.declaration.helper.nftables
push: helper-specs
- match: (})
scope: punctuation.section.block.end.table.nftables
pop: true
chain-specs:
- match: \b({{identifier_extended}})\b
scope: entity.name.chain.nftables
set:
- match: ({)
scope: punctuation.section.block.begin.chain.nftables
set:
- meta_scope: meta.block.chain.nftables
# Chain settings.
- include: _consume-rule-matches-type
- match: \b(type)\b
scope: storage.type.chain-type.nftables
push:
- match: ({{chain_types}})
scope: constant.language.chain-type.nftables
set:
- match: \b(hook)\b
scope: storage.type.chain-hook.nftables
set:
- match: ({{chain_hooks}})
scope: constant.language.hook.nftables
set:
- match: \b(device)\b
scope: storage.type.chain-device.nftables
push: _expect-unquoted-string
- match: \b(priority)\b
scope: storage.type.chain-priority.nftables
set:
- match: ({{chain_types}})
scope: constant.language.chain-type.nftables
- include: signed-integer
- include: plus-or-dash
- include: statement-separators
# Chain policy.
- match: \b(policy)\b
scope: storage.type.chain-policy.nftables
push:
- match: \b(accept|drop)\b
scope: constant.language.chain-policy.nftables
- include: statement-separators
# Chain rules.
- include: rule-definitions
- include: semi-colon
- match: (})
scope: punctuation.section.block.end.chain.nftables
pop: true
flowtable-specs:
- match: \b({{identifier_extended}})\b
scope: entity.name.flowtable.nftables
set:
- match: ({)
scope: punctuation.section.block.begin.flowtable.nftables
set:
- meta_scope: meta.block.flowtable.nftables
# Flowtable settings.
- match: \b(hook)\b
scope: storage.type.flowtable-hook.nftables
push:
- match: ({{chain_hooks}})
scope: constant.language.hook.nftables
set:
- match: \b(priority)\b
scope: storage.type.flowtable-priority.nftables
set:
- match: ({{chain_types}})
scope: constant.language.chain-type.nftables
- include: signed-integer
- include: plus-or-dash
- match: \b(devices)\b
scope: storage.type.flowtable-devices.nftables
set: assignment
- include: semi-colon
- match: (})
scope: punctuation.section.block.end.flowtable.nftables
pop: true
set-specs:
- match: \b({{identifier_extended}})\b
scope: entity.name.set.nftables
set:
- match: ({)
scope: punctuation.section.braces.begin.named-set.nftables
set:
- meta_scope: meta.object.named-set.nftables
- match: \b(type)\b
scope: storage.type.set-type.nftables
push:
- match: \b((?:ipv[46]|ether)_addr|inet_(?:proto|service)|counter|ifname|mark)\b
scope: constant.language.data-type.nftables
- include: dot-operator
- include: colon
- include: verdict-statements
- match: \b(verdict)\b
scope: constant.language.verdict.nftables
- include: statement-separators
- match: \b(timeout)\b
scope: storage.type.set-timeout.nftables
push:
- include: time-string
- include: statement-separators
- match: \b(flags)\b
scope: storage.type.set-flags.nftables
push:
- match: \b(constant|interval|timeout)\b
scope: constant.language.set-flag.nftables
- include: comma
- include: statement-separators
- match: \b(gc\-interval)\b
scope: storage.type.set-gcinterval.nftables
push:
- include: time-string
- include: statement-separators
- match: \b(elements)\b
scope: storage.type.set-elements.nftables
push:
- include: assignment
- include: statement-separators
- match: \b(size)\b
scope: storage.type.set-size.nftables
push:
- include: signed-integer
- include: statement-separators
- match: \b(policy)\b
scope: storage.type.set-policy.nftables
push:
- match: \b(performance|memory)\b
scope: constant.language.set-policy.nftables
- include: statement-separators
- include: semi-colon
- match: (})
scope: punctuation.section.braces.end.named-set.nftables
pop: true
quota-specs:
- match: \b({{identifier_extended}})\b
scope: entity.name.quota.nftables
set:
- include: integer
- match: \b(over|until)\b
scope: constant.language.quota-mode.nftables
push: _expect-integer
- match: \b(used)\b
scope: constant.language.quota-used.nftables
push: _expect-integer
- include: statement-separators
helper-specs:
- match: \b({{identifier_extended}})\b
scope: entity.name.helper.nftables
set:
- match: ({)
scope: punctuation.section.braces.begin.helper.nftables
set:
- meta_scope: meta.object.helper.nftables
- match: \b(type)\b
scope: storage.type.helper-type.nftables
push:
- include: quoted-string
- match: \b(protocol)\b
scope: storage.type.helper-protocol.nftables
set:
- match: \b(tcp|udp)\b
scope: constant.language.l4-proto.nftables
- include: statement-separators
- match: \b(l3proto)\b
scope: storage.type.helper-l3proto.nftables
push:
- match: ({{family_types}})
scope: constant.language.family-type.nftables
- include: statement-separators
- include: semi-colon
- match: (})
scope: punctuation.section.braces.end.helper.nftables
pop: true
family-types:
- match: ({{family_types}})
scope: constant.language.family-type.nftables
table-flags:
- match: \b(flags)\b
scope: storage.type.table-flags.nftables
push:
- match: \b(dormant)\b
scope: constant.language.table-flag.nftables
- include: comma
- include: statement-separators
verdict-statements:
- match: \b(accept|drop|queue|continue|return)\b
scope: keyword.control.rule-statement.verdict.nftables
- match: \b(jump|goto)\b
scope: keyword.control.rule-statement.verdict.nftables
push:
- match: \b({{identifier_extended}})\b
scope: variable.other.readwrite.chain.nftables
pop: true
rule-definitions:
# Allows many various tokens in rules (additionally to `prototype`).
- include: safe-values
- include: operators
- include: comma
- include: colon
# Consumes and scopes known stateful objects keywords.
- match: \b(v?map)\b
scope: storage.type.map.nftables keyword.declaration.map.nftables
- match: \b(quota)\b
scope: storage.type.quota.nftables keyword.declaration.quota.nftables
- match: (?:\bct\b\s+\b(helper)\b)
captures:
1: storage.type.helper.nftables keyword.declaration.helper.nftables
# Each rules should (might ?) have (non-)terminal statement(s).
- include: verdict-statements
- include: _consume-status-nat
- match: |-
(?x)
\b(
log|reject|counter|limit|comment|
(?:s|d)nat|masquerade|redirect|dup|fwd|
set|flow|notrack
)\b
scope: keyword.control.rule-statement.nftables
operators:
- match: \b(eq|ne|(?:l|g)[et]|numgen|jhash)\b
scope: keyword.operator.arithmetic.nftables
- match: (&|\||\<\<|\>\>|\^)
scope: keyword.operator.bitwise.nftables
- match: ([!=]=|[\<\>]=?)
scope: keyword.operator.arithmetic.nftables
- match: \b(and|x?or)\b
scope: keyword.operator.arithmetic.nftables
- include: plus-or-dash
- include: dot-operator
plus-or-dash:
- match: \B(\+|\-)\B
scope: keyword.operator.arithmetic.nftables
dot-operator:
- match: \B(\.)\B
scope: keyword.operator.concatenation.nftables
# Below contexts require further explanations.
# Sublime Text >= 3103 ships a specific optimized REGEXP engine, not supporting look-behinds.
# See <https://www.sublimetext.com/blog/articles/sublime-text-3-build-3103> for external reference.
#
# In order to make this syntax definition working against this engine, we have to get rid of look-behinds.
# As a workaround, we define here contexts that consume tokens we shouldn't be matching elsewhere.
_consume-rule-matches-type:
# Consume some rule matches using the `type` keyword".
- match: (?:\b(?:ether|dccp|icmp(?:v6|x)?|mh|rt)\b\s+\btype\b)
# Consumes `fib ${key} ${data}` (as `data` **MIGHT** be `type`).
# See <https://wiki.nftables.org/wiki-nftables/index.php/Routing_information#fib>.
- match: \bfib\b
push:
# `${key}` might be the dot operator (`.`), so we must match it as well.
- include: dot-operator
# We assume that `fib` must be followed by a (known) `${data}` expression.
# So the first encountered one will act as a cue to leave this context.
- match: \b(oif(?:name)?|type)\b
pop: true
_consume-status-nat:
# Consume `ct status` rule matches using `(s|d)nat`.
- match: (?:\bct\b\s+\bstatus\b\s+\b(?:s|d)nat\b)