- Overview
- Key features
- Requirements
- Installation
- Quick start
- CLI reference
- Configuration format
- Matching behavior
- Output formats
- Examples
- Testing
- Releases
- Troubleshooting
- Development
- API reference
- Config schema appendix
- License
- Docs
VyFwMatch is a modular VyOS firewall policy testing tool that parses VyOS boot configuration files and evaluates firewall rules for a given traffic tuple. It follows VyOS first-match-wins behavior, supports IPv4 and IPv6 chains, and resolves group references (address, network, port, interface).
The tool is designed as a wrapper around the official VyOS codebase (vyos-1x
submodule), using VyOS's own configuration parsing when available, and provides
a minimal decision engine for offline firewall rule simulation.
- Parses VyOS boot config files (not
setcommand format) - Supports
forward,input, andoutputhooks (default isforward) - Evaluates chains with jump/continue/return semantics
- Resolves group references for matching
- Accepts service names or raw ports
- Outputs results in table (default) or JSON
- Python 3.10+ (tested with 3.13)
- pytest for running tests
- pylint for code quality checks
VyFwMatch uses VyOS's original validators for configuration validation. For full validation capabilities, you need to build two binaries:
- ipaddrcheck - IP address validation (C-based)
- validate-value - Regex validation (OCaml-based)
Note: Python fallback validators are available when binaries aren't built, providing basic validation without external dependencies.
# Install build tools
sudo apt-get install autoconf automake libtool gcc make \
libcidr-dev libpcre2-dev opam ocaml dune
# Build both binaries using Make
make build-deps# Install build tools via Homebrew
brew install autoconf automake libtool pcre2 opam dune
# Note: libcidr needs to be built from source on macOS
# The binaries are primarily for Linux/Docker deployment
# For local development, Python fallbacks work without buildingThe Docker build automatically compiles both binaries:
docker build -t vyfwmatch:latest .Clone the repository and install in editable mode:
git clone <repository-url>
cd vyos-fw-match
python -m venv venv
source venv/bin/activate
pip install -e .This will install the vyfwmatch command-line tool.
If you prefer not to install the package:
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python vyfwmatch/main.py --helpUsing the installed command:
vyfwmatch \
--config example/sample_config.boot \
--inbound-interface eth0 \
--source 10.0.0.1 \
--destination 192.168.0.10 \
--service httpsOr running from source:
python vyfwmatch/main.py \
--config example/sample_config.boot \
--inbound-interface eth0 \
--source 10.0.0.1 \
--destination 192.168.0.10 \
--service httpsRequired arguments:
--configPath to VyOS boot config file--inbound-interfaceInbound interface name--sourceSource IP address (must be an IP)--destinationDestination IP address (must be an IP)- At least one of
--serviceor--protocol
Optional arguments:
--outbound-interfaceOutbound interface name--hookHook to evaluate (forward,input,output), default isforward--serviceService name or port (e.g.http,443)--protocolProtocol (e.g.tcp,udp,icmp)--portDestination port number (use with--protocol)--stateConnection state (new,established,related,invalid)--formatOutput format (tableorjson)
Only the VyOS boot configuration format is supported (curly-brace hierarchy).
The tool does not accept set commands.
Supported elements include:
firewall { ipv4 { ... } ipv6 { ... } }- Base chains:
forward,input,output - Named chains:
name <CHAIN> - Group definitions under
firewall { group { ... } }
- First-match-wins evaluation (top-down within a chain)
jumpevaluates a target chain;returnresumes the callercontinueskips to the next rule- If no rule matches, the chain
default-actionis applied - Global
state-policyis evaluated only if no chain rule matched
tableshows the selected chain, rule, action, criteria, and tracejsonreturns structured output suitable for scripting
Forwarded HTTPS traffic:
vyfwmatch \
--config example/sample_config.boot \
--inbound-interface eth0 \
--source 10.0.0.1 \
--destination 192.168.0.10 \
--service httpsInput traffic to the router itself:
vyfwmatch \
--config example/sample_config.boot \
--inbound-interface eth0 \
--source 1.2.3.4 \
--destination 192.168.0.1 \
--protocol icmp \
--hook inputProtocol + port without service name:
vyfwmatch \
--config example/sample_config.boot \
--inbound-interface eth0 \
--source 10.0.0.1 \
--destination 192.168.0.10 \
--protocol tcp \
--port 443Run the full test suite:
pytest
# or using Make
make testRun with coverage:
pytest --cov=vyfwmatch --cov-report=html
# or using Make
make test-covRun pylint for code quality:
pylint vyfwmatch/
# or using Make
make lintRun all checks:
make checkThis repository uses semantic-release in CI for automated versioning, tags, changelog updates, and GitHub releases.
- Releases run automatically on pushes to
mainafter lint/test/security jobs pass. - Version bumps are inferred from commit messages using Conventional Commits.
Commit types used for release bumping:
fix:-> patch release (e.g.1.2.3->1.2.4)feat:-> minor release (e.g.1.2.3->1.3.0)feat!:orBREAKING CHANGE:-> major release (e.g.1.2.3->2.0.0)
Examples:
fix(validators): trim whitespace in address and port validation
feat(ci): add release notes publication
feat!: remove legacy rule loader fallback
-
"Configuration validation failed: Invalid network prefix"
- Ensure all IP addresses and networks use valid CIDR notation
- Build the ipaddrcheck binary for comprehensive IP validation
- Python fallbacks provide basic validation without the binary
-
"Configuration validation failed: Invalid port"
- Check port ranges are valid (1-65535)
- Ensure port ranges have start <= end (e.g., "80-443" not "443-80")
-
"Configuration validation failed: Jump target not found"
- Ensure all
jump-targetvalues reference existing chains - Chain names are case-sensitive
- Ensure all
- Error:
--destination must be an IP address- Provide an IP address instead of an FQDN
- Error:
--source must be an IP address- Provide an IP address instead of an FQDN
- Error:
Unknown service- Use a numeric port or a supported service name
- No matching chain
- Ensure the config includes the selected hook (
forward,input,output)
- Ensure the config includes the selected hook (
Development
The project follows a modular, layered architecture:
- Entry point:
vyfwmatch/main.py- Main CLI entry point - CLI layer:
vyfwmatch/cli/- Argument parsing and output formattingargument_parser.py- CLI argument validationoutput_formatter.py- Result formatting (table/JSON)
- Service layer:
vyfwmatch/services/- Business logicraw_config_validator.py- Validates config before parsing (NEW)vyos_validators.py- VyOS validator wrappers (NEW)rule_loader.py- Loads firewall config from VyOS configdecision_engine.py- Evaluates rules against traffic tupleshelpers.py- IP/port/interface matching utilities and service resolution
- Domain layer:
vyfwmatch/domain/- Core modelsmodels.py- Domain models (Rule, Chain, FirewallConfig, etc.)
- Adapter layer:
vyfwmatch/adapters/- External integrationsvyos_config.py- VyOS configuration adapterconfig_parser.py- VyOS boot config tokenizer and parser
All functionality is self-contained within the vyfwmatch/ package.
The project maintains high code quality standards:
- Pylint score: 9.96/10
- Python version: 3.10+ minimum
- Test coverage: 177 tests, all passing
- Type hints: Used throughout all modules
API reference
The primary interface is the CLI. Internal APIs are documented in:
docs/api.md
See docs/config-schema.md for supported config elements and examples.
MIT License. See LICENSE.
docs/index.mddocs/architecture.mddocs/tests/README.mddocs/api.mddocs/config-schema.md