One policy
PF-style rules describe filtering, NAT, routing intent, queues, tables, and logging in one file.
Next-generation Linux firewall
Linux packet policy is powerful, but it is split across nftables, policy routing, tc, conntrack, rollback files, and logging. lpf was created to make that surface readable, reviewable, testable, and safe to apply on remote machines.
PF-style rules describe filtering, NAT, routing intent, queues, tables, and logging in one file.
Plans, diffs, guarded apply, confirmation timers, history, and rollback are part of the operating model.
Operators can ask what would change, why a packet matched, and what state must be restored before touching production networking.
Use the native Debian or RPM package for a host install. Clone the repository only when you want the OCaml build, tests, and fixtures locally.
$ 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.2.1
$ opam install . \
--deps-only --with-test
$ dune build
$ dune runtest
Use policy files as code: validate before touching the host, inspect live drift, ask why a packet matches, 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