How cmnSense is built
Most open source firewalls grew from a web application that writes configuration files and runs shell commands. cmnSense starts from the other end: a typed configuration model, a language to express it, and the kernel's own interfaces to apply it.
A configuration language, with a complete CLI
The configuration is written in the language network engineers already read: interface, nameif, object-group, access-list, nat (lan,wan), router bgp. The file is not parsed by a separate parser. Loading it replays every line as a CLI command against an empty configuration, the way a router replays its startup configuration, so every line of a file is a valid command and every command has a line in the file.
- The CLI covers the whole configuration and every status view; the web interface edits the same configuration.
- Abbreviations, context help with
?, Tab completion,noto negate any command, output filters and paging. - A running and a startup configuration with
write memory, and the canonical text form round-trips exactly, which the test suite checks. - Strict, bounded parsing: sizes, nesting and every value are validated before anything is applied.
Native kernel interfaces, no shell tools
Network configuration never goes through ip, nft, iptables, conntrack or ipvsadm, and no command output is parsed to find out what the system looks like. The management server speaks netlink to the kernel directly:
| What | Kernel interface |
|---|---|
| Links, VLANs, bridges, bonds, tunnels | rtnetlink |
| Addresses and routes | rtnetlink |
| Firewall and NAT | nf_tables, one batch transaction |
| Connection tracking and state sync | ctnetlink |
| WireGuard | generic netlink |
| L2TPv3 pseudowires | generic netlink |
| IPVS load balancing | generic netlink |
The whole ruleset is compiled and loaded as one nf_tables transaction, so the kernel switches from the old policy to the new one in a single step and a rejected change leaves the old one in place. The server watches the kernel for changes made behind its back and puts its state back. The services around the network are a different matter and are driven the way their authors intend: strongSwan over its VICI protocol, Kea through its control agent, and FRR with its own configuration language, checked by FRR's parser before it is loaded.
API first, with an OpenAPI 3.1 contract
There is one way to change a cmnSense firewall: the management API. The web interface is a client of it, and so is the CLI, which reaches it over a local socket that identifies the user from the kernel rather than a password. The API is described by an OpenAPI 3.1 contract, so automation gets the same validation, the same role checks and the same configuration history as a person at the keyboard.
No PHP, no database, no shell in the request path
- The management server is written in Rust and runs as an unprivileged user with only
CAP_NET_ADMIN, in a sandboxed systemd unit with a system call filter. - The typed configuration model is the database, and the text file is its canonical form. A change is validated on a copy, written atomically and applied with rollback; a failure at any step leaves the old configuration running.
- Web sessions are random tokens stored only as hashes, logins are throttled, and SSH users land in the CLI, never in a shell.
- Passkeys (WebAuthn) are built in: phishing-resistant, username-less sign-in with user verification, where the firewall holds only public keys.
Serious networking underneath
Because nothing stands between the configuration and the kernel, cmnSense can offer what the kernel offers.
interface bridge2
vlan-aware
!
interface po1
nameif pwlag
lacp rate fast
ip address 192.168.250.1/30
!
interface l2tp0
l2tp local 10.100.0.254
l2tp remote 10.100.0.1
l2tp id 1000 2000
channel-group 1 mode active
!
interface vxlan200
vxlan vni 200
vxlan source 10.100.0.254
vxlan remote 10.100.0.1
bridge-group 2
switchport mode trunk
switchport trunk allowed vlan 300-301
- VLANs, VLAN-aware bridges with access and trunk ports, LACP port-channels and loopbacks.
- GRE, GRETAP, VXLAN, WireGuard, route-based IPsec and L2TPv3 pseudowires, which can themselves be bundled with LACP.
- IPv6 throughout: addresses, autoconfiguration, router advertisements, VRRPv3, DHCPv6, OSPFv3 and IS-IS.
- BGP, OSPF, IS-IS and BFD with FRR, policy routing, and gateway groups with health monitoring.
- A full layer 4 load balancer in the kernel with IPVS, with health probes, Maglev scheduling and its connection table synchronised across an HA pair.
Compared with other firewall distributions
Each of these is a capable firewall, and the choice depends on what you need. This is about how they are built.
pfSense is a trademark of Rubicon Communications (Netgate), OPNsense of Deciso B.V., and VyOS of VyOS Inc. They are named here only to describe their published designs.
See the features, or download cmnSense and try it.