One policy
One PF-style file describes filtering, NAT, routing, queues, tables, and logging.
Next-generation Linux firewall with PF-style policy
Linux packet policy spans nftables, routing, tc, conntrack, and logging. lpf unifies them into a single PF-style policy file with guarded deployment, packet explainability, and formal Z3 verification.
One PF-style file describes filtering, NAT, routing, queues, tables, and logging.
Plans, diffs, guarded apply, confirmation timers, history, and rollback.
Ask what would change, why a packet matched, and what state gets restored before applying.
# nftables + routing + tc + conntrack + logging → lpf
One source file is checked, lowered to a typed IR, planned, proven with Z3, then applied behind a rollback timer onto an nftables or eBPF datapath. Every stage is inspectable.
# check → IR → plan → verify → apply → datapath
# no confirm → automatic rollback
# lpf explain traces this path for any packet
# XDP drops before sk_buff · per-CPU counters · ring buffer events
Native .deb and .rpm packages on GitHub Releases. Clone the repo for the OCaml build, tests, and fixtures.
$ OUT=/tmp/lpf-release && mkdir -p "$OUT"
$ gh release download \
--repo ingresslabs/lpf \
--pattern 'lpf_*_amd64.deb' \
--dir "$OUT"
$ sudo apt install "$OUT"/lpf_*_amd64.deb
$ OUT=/tmp/lpf-release && mkdir -p "$OUT"
$ gh release download \
--repo ingresslabs/lpf \
--pattern 'lpf-*.x86_64.rpm' \
--dir "$OUT"
$ sudo dnf install "$OUT"/lpf-*.x86_64.rpm
$ git clone https://github.com/ingresslabs/lpf.git && cd lpf
$ opam switch create . ocaml-base-compiler.5.1
$ opam install . --deps-only --with-test
$ dune build && dune runtest
Policy files as code: validate, inspect drift, trace packets, then apply with a confirmation timer.
$ lpf check /etc/lpf.conf
$ lpf fmt --check /etc/lpf.conf
$ lpf plan --json /etc/lpf.conf
$ lpf diff --live /etc/lpf.conf
$ lpf apply --confirm 60s /etc/lpf.conf
# verify the session still reaches the host
$ lpf confirm
$ lpf explain --src 10.0.0.5 --dst 1.1.1.1 \
--dport 443 --tcp --in /etc/lpf.conf
set default deny
interface wan = "eth0"
table <admin> { 198.51.100.10, 203.0.113.0/24 }
pass in log on wan proto tcp from any to any port 80
pass in log on wan proto tcp from any to any port 443
pass in log (user) on wan proto tcp from <admin> to any port 22 keep state
block in log (all) on wan proto tcp from any to any port 22
pass out on wan proto udp from any to any port 53 keep state
pass out on wan proto tcp from any to any port 80 keep state
pass out on wan proto tcp from any to any port 443 keep state
block in log from any to any
set default deny
interface app = "eth1"
interface wan = "eth0"
table <admin> { 198.51.100.10, 203.0.113.0/24 }
table <apps> { 10.20.0.10, 10.20.0.11 }
rdr on wan proto tcp from any to any port 80 -> 10.20.0.10 port 8080
rdr on wan proto tcp from any to any port 443 -> 10.20.0.10 port 8443
pass in log on wan proto tcp from any to any port 80
pass in log on wan proto tcp from any to any port 443
pass in on app proto tcp from <apps> to any port 8080 keep state
pass in on app proto tcp from <apps> to any port 8443 keep state
pass in log (user) on wan proto tcp from <admin> to any port 22 keep state
pass out on wan proto tcp from any to any port 443 keep state
block in log from any to any
set default deny
interface lan = "eth1"
interface wan = "eth0"
table <blocked> { 10.0.0.66, 10.0.0.67 }
table <lan_hosts> { 10.0.0.0/24 }
nat on wan from <lan_hosts> to any -> wan
block in log (user) on lan from <blocked> to any
pass in on lan from <lan_hosts> to any
pass out on wan proto udp from <lan_hosts> to any port 53 keep state
pass out on wan proto tcp from <lan_hosts> to any port 80 keep state
pass out on wan proto tcp from <lan_hosts> to any port 443 keep state
pass out on wan proto icmp from <lan_hosts> to any keep state
block out log (all) on wan from any to any
set default deny
interface uplink = "wlan0"
table <dns> { 1.1.1.1, 9.9.9.9 }
table <update_mirrors> { 198.51.100.20, 203.0.113.20 }
pass out on uplink proto udp from any to <dns> port 53 keep state
pass out on uplink proto tcp from any to any port 80 keep state
pass out on uplink proto tcp from any to any port 443 keep state
pass out on uplink proto udp from any to any port 123 keep state
pass out on uplink proto tcp from any to <update_mirrors> port 22 keep state
block in log (all) on uplink from any to any
block out log (user) on uplink from any to any
set default deny
interface lan = "eth1"
interface wan = "eth0"
table <admin> { 10.0.0.10, 10.0.0.11 }
table <clients> { 10.0.0.0/24, 192.168.10.0/24 }
table <upstream_dns> { 1.1.1.1, 9.9.9.9 }
pass in log on lan proto udp from <clients> to any port 53
pass in log on lan proto tcp from <clients> to any port 53
pass out on wan proto udp from any to <upstream_dns> port 53 keep state
pass out on wan proto tcp from any to <upstream_dns> port 53 keep state
pass in on lan proto tcp from <admin> to any port 22 keep state
block in log (user) on wan proto udp from any to any port 53
block in log (user) on wan proto tcp from any to any port 53
block in log from any to any