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, no to 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:

How cmnSense is arrangedBrowsers and automation reach nginx over HTTPS, SSH users reach the cmnsense-cli program. Both talk to cmnsense-server over local sockets. The server holds the typed configuration model, validates and records every change, programs the Linux kernel over netlink and drives FRR, Kea, strongSwan, dnsmasq and chrony through their own control interfaces.clientsBrowserHTTPSAutomationREST APISSHuser's own loginnginxTLS, rate limitscmnsense-clicmnsense-servertyped configuration modelvalidation and rollbackhistory of every changeOpenAPI 3.1 APIunprivileged · CAP_NET_ADMIN onlyweb.sockcli.sockLinux kernelrtnetlinknf_tablesctnetlinkWireGuardL2TPv3IPVSnetlinkFRRKeastrongSwandnsmasqchronynative control interfacesservices around the network
WhatKernel interface
Links, VLANs, bridges, bonds, tunnelsrtnetlink
Addresses and routesrtnetlink
Firewall and NATnf_tables, one batch transaction
Connection tracking and state syncctnetlink
WireGuardgeneric netlink
L2TPv3 pseudowiresgeneric netlink
IPVS load balancinggeneric 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.

interfaces and tunnels
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.

cmnSensepfSense and OPNsenseVyOS
Base systemStock Debian 13, installed as packagesFreeBSD, built as its own distributionDebian based, installed as its own image
Packet filternftablespfnftables
ConfigurationOne IOS-style text file, replayed line by line as CLI commandsOne XML documentA hierarchical tree edited with set and commit
Command lineThe complete configuration and every show command, ASA and IOS styleA console menu and a shellA complete Junos-style CLI
Management stackA Rust server holding one typed configuration modelA PHP web applicationPython scripts behind the CLI
Network changesNetlink messages straight to the kernel, nftables as one atomic transactionGenerated rule sets and system commandsGenerated configuration files and system commands
APIThe only way in: the web interface and the CLI are API clients, described by an OpenAPI 3.1 contractAdded alongside the web interfaceAn HTTP API wrapping the CLI

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.