lpf
lpf
Next-generation Linux firewall
PF-style syntax<br>nftables first<br>safe remote apply<br>JSON ready
Why
Linux firewalling should feel like one system.
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.
One policy
PF-style rules describe filtering, NAT, routing intent, queues, tables, and logging in one file.
Safe changes
Plans, diffs, guarded apply, confirmation timers, history, and rollback are part of the operating model.
Explainable operations
Operators can ask what would change, why a packet matched, and what state must be restored before touching production networking.
Install
Install from GitHub Releases.
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.
Debian / Ubuntu
$ OUT=/tmp/lpf-release<br>$ mkdir -p "$OUT"<br>$ gh release download \<br>--repo ingresslabs/lpf \<br>--pattern 'lpf_*_amd64.deb' \<br>--dir "$OUT"<br>$ sudo apt install "$OUT"/lpf_*_amd64.deb
RPM hosts
$ OUT=/tmp/lpf-release<br>$ mkdir -p "$OUT"<br>$ gh release download \<br>--repo ingresslabs/lpf \<br>--pattern 'lpf-*.x86_64.rpm' \<br>--dir "$OUT"<br>$ sudo dnf install "$OUT"/lpf-*.x86_64.rpm
Source checkout
$ git clone \<br>https://github.com/ingresslabs/lpf.git<br>$ cd lpf<br>$ opam switch create . \<br>ocaml-base-compiler.5.2.1<br>$ opam install . \<br>--deps-only --with-test<br>$ dune build<br>$ dune runtest
Usage
Check first. Diff live. Apply guarded.
Use policy files as code: validate before touching the host, inspect live drift, ask why a packet matches, then apply with a confirmation timer.
Policy loop
$ lpf check /etc/lpf.conf<br>$ lpf fmt --check /etc/lpf.conf<br>$ lpf plan --json /etc/lpf.conf<br>$ lpf diff --live /etc/lpf.conf
Guarded deploy
$ lpf apply --confirm 60s /etc/lpf.conf<br># verify the session still reaches the host<br>$ lpf confirm
Explain a packet
$ lpf explain --src 10.0.0.5 --dst 1.1.1.1 --dport 443 --tcp --in /etc/lpf.conf
Configs
Policy examples
Web server public HTTP/HTTPS, restricted SSH
set default deny
interface wan = "eth0"
table { 198.51.100.10, 203.0.113.0/24 }
pass in log on wan proto tcp from any to any port 80<br>pass in log on wan proto tcp from any to any port 443<br>pass in log (user) on wan proto tcp from to any port 22 keep state<br>block in log (all) on wan proto tcp from any to any port 22<br>pass out on wan proto udp from any to any port 53 keep state<br>pass out on wan proto tcp from any to any port 80 keep state<br>pass out on wan proto tcp from any to any port 443 keep state<br>block in log from any to any
Reverse proxy public redirects to internal app listeners
set default deny
interface app = "eth1"<br>interface wan = "eth0"
table { 198.51.100.10, 203.0.113.0/24 }<br>table { 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<br>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<br>pass in log on wan proto tcp from any to any port 443<br>pass in on app proto tcp from to any port 8080 keep state<br>pass in on app proto tcp from to any port 8443 keep state<br>pass in log (user) on wan proto tcp from to any port 22 keep state<br>pass out on wan proto tcp from any to any port 443 keep state<br>block in log from any to any
NAT gateway LAN masquerade and controlled egress
set default deny
interface lan = "eth1"<br>interface wan = "eth0"
table { 10.0.0.66, 10.0.0.67 }<br>table { 10.0.0.0/24 }
nat on wan from to any -> wan
block in log (user) on lan from to any<br>pass in on lan from to any<br>pass out on wan proto udp from to any port 53 keep state<br>pass out on wan proto tcp from to any port 80 keep state<br>pass out on wan proto tcp from to any port 443 keep state<br>pass out on wan proto icmp from to any keep state<br>block out log (all) on wan from any to any
Workstation egress default-deny client outbound policy
set default deny
interface uplink = "wlan0"
table { 1.1.1.1, 9.9.9.9 }<br>table { 198.51.100.20, 203.0.113.20 }
pass out on uplink proto udp from any to port 53 keep state<br>pass out on uplink proto tcp from any to any port 80 keep state<br>pass out on uplink proto tcp from any to any port 443 keep state<br>pass out on uplink proto udp from any to any port 123 keep state<br>pass out on uplink proto tcp from any to port 22 keep state<br>block in log (all) on uplink from any to any<br>block out log (user) on uplink from any to any
DNS resolver LAN clients, upstream DNS, admin SSH
set default deny
interface lan = "eth1"<br>interface wan = "eth0"
table { 10.0.0.10, 10.0.0.11 }<br>table { 10.0.0.0/24, 192.168.10.0/24 }<br>table { 1.1.1.1, 9.9.9.9 }
pass in log on lan proto udp from to any port 53<br>pass in log on lan proto tcp from to any port 53<br>pass out on wan proto udp from any to port 53 keep state<br>pass out on wan proto tcp from any to port 53 keep state<br>pass in on lan proto tcp from to any port 22 keep...