ufw-rule-parser
ufw-rule-parser is a parser for a small ufw-like firewall rule language.
it uses the pest parsing library and a custom grammar defined in grammar.pest.
it supports address-based rules, service-based rules, and special address keywords such as internal and external.
example rules
allow ssh
allow in on eth0 from internal to external port 443 proto tcp
deny out to 8.8.8.8 port 53 proto udp
cli usage
parse a rules file and print the structured output:
output as json format:
write json output to a file:
short form for output flag:
show help:
show credits:
output formats
the parser supports two output formats:
- debug format (default): pretty-printed rust structs showing the parsed rules.
- json format: structured json output with typed fields. use
--jsonflag to enable.
when using --output or -o flag, json is written to the specified file instead of stdout.
the --output flag requires the --json flag to be set.
project structure
src/grammar.pestdefines the grammar used by the parsersrc/lib.rsexposes the parser api and typed ast structuressrc/main.rsimplements the cli interfacetests/grammar_tests.rscontains unit tests for each grammar ruletests/parser_tests.rscontains integration tests for ast parsingexamples/contains sample rule files for testing
grammar overview
grammar diagram
file
└── line* (zero or more lines)
├── service_rule
│ └── action + ident
├── addr_rule
│ ├── action (required)
│ ├── direction? (optional)
│ ├── interface_clause? (optional)
│ └── (from_clause | to_clause | port_clause | proto_clause)+ (one or more)
└── COMMENT? (optional comment)
grammar rules
the grammar in grammar.pest defines rules using pest syntax:
action: matchesallow,deny,reject, orlimitdirection: matchesinoroutident: matches identifiers with letters, numbers, underscores, and dashesip: matches ip addresses and cidr notationaddr: matchesany,internal,external, or ip addressesport_clause: matchesportfollowed by a numberproto_clause: matchesprotofollowed bytcp,udp, oranyinterface_clause: matchesonfollowed by an identifierfrom_clauseandto_clause: matchfromortofollowed by an addressaddr_rule: combines action, optional direction, optional interface, and one or more clausesservice_rule: matches action followed by an identifierline: matches a rule with optional comment, or just a commentfile: matches multiple lines from start to end of input
the grammar supports:
- actions:
allow,deny,reject,limit - directions:
in,out - interfaces:
on eth0 - addresses:
any,internal,external, or ip/cidr - service rules such as
allow ssh - address-based rules combining direction, from/to, ports, and protocol
parsing process
the parser reads input text and matches it against the grammar rules.
pest produces a structured tree of pairs that describe which rule matched each part of the input.
the library converts these pairs into typed rust structures (firewallrule, servicerule, addressrule).
integration tests verify that the grammar accepts valid rules and rejects invalid ones.
testing
run all tests:
format code:
lint code:
use the makefile for common tasks: