Novo pipeline de video: scripts/screencast/render.py roda uma fase em um pty,
emula o terminal com pyte, gera frames PNG e mux com ffmpeg (H.264,
yuv420p, +faststart, sem trilha de audio). Fallback de encoder: libx264 ->
libopenh264 -> VP9.
Fases (scripts/screencast/phases/, uma sessao real contra o lab por video):
1. implementacao no kernel - fontes OpenBSD + compat + build limpo do pf.ko
2. ativacao - insmod, /dev/pf, pfctl -e, pfctl -s info
3. regras basicas - tabela, anchor, keep state, block drop
4. roteamento - route-to e reply-to (provado com tcpdump nas 2 interfaces)
5. balanceamento - pool round-robin, pool source-hash, dup-to
6. QOS - filas hfsc, pfctl -s queue -v, transferencia de 2 MB pela fila
Os videos ficam versionados em out/screencast/ (.gitignore ajustado para
nao ignorar *.mp4) e o indice/texto de descricao do YouTube em
docs/{en,pt-BR}/screencast.md.
Correcoes na propria demo (encontradas gravando): a acao de uma regra no pf
e pass OU block (nunca os dois); as regras de um anchor vivem em um ruleset
proprio (pfctl -a <anchor> -f); o nc do QOS precisa rodar na VM do servidor,
nao no firewall; o rotulo 'FASE x/6' vem do numero da fase, nao da posicao
na lista de gravacao.
100 lines
5.5 KiB
Markdown
100 lines
5.5 KiB
Markdown
# PF on Linux
|
||
|
||
Port of the OpenBSD **PF** (packet filter) to **Linux 7.3.4** as an
|
||
out-of-tree kernel module — the real PF engine (`pf.c`, `pf_norm.c`,
|
||
`pf_table.c`, `pf_lb.c`, … ported from OpenBSD 8.0 sources) driven by the
|
||
real OpenBSD `pfctl` over the `/dev/pf` ioctl ABI. (A second module for the
|
||
`pfq` qdisc arrives with M5.)
|
||
|
||
**Status:** the filter core, stateful filtering, tables, anchors, NAT
|
||
(`nat-to`/`rdr-to`/`binat-to`), forced routing (`route-to`/`dup-to`), `divert`
|
||
and `pflog` are **verified in a real libvirt lab** (14/14 gates green). The
|
||
remaining features (queue attachment/pacing, af-to) are still pending — honest per-feature status:
|
||
[`docs/en/feature-matrix.md`](docs/en/feature-matrix.md).
|
||
Demo (asciinema): [`docs/en/demo.md`](docs/en/demo.md).
|
||
Design: [`docs/superpowers/specs/2026-11-11-pf-linux-port-design.md`](docs/superpowers/specs/2026-11-11-pf-linux-port-design.md)
|
||
· plan: [`docs/superpowers/plans/2026-11-11-pf-linux-port.md`](docs/superpowers/plans/2026-11-11-pf-linux-port.md).
|
||
|
||
## Milestones
|
||
|
||
| Milestone | Scope | Status (2026-11-11) |
|
||
|---|---|---|
|
||
| M0 | repo, scripts, kernel build, VM boots the custom kernel | done |
|
||
| M1 | compat layer, `pf.ko` loads, `/dev/pf`, `pfctl -f` / `-s info` | done |
|
||
| M2 | filter core: rules/states/tables/anchors, VM gates 01–04 | **done** — gates 01/02/03/04 green |
|
||
| M3 | NAT (`nat-to`/`rdr-to`/`binat-to`), scrub | **done** — gates 05/06/07/09 (incl. 2 MB integrity through a redirect, min-ttl/max-mss measured) |
|
||
| M4 | route-to/dup-to/reply-to, divert e2e, pflog | **done** — divert (11), pflog (12), route-to/dup-to (08), pools (10), reply-to (13) verified |
|
||
| M5 | queues: HFSC back end in the data path | **done (mechanical)** — gate 15: queues load, hfsc attaches, `pfctl -s queue -v` reports class stats, a 2 MB queued flow is counted by the class. `bandwidth` = HFSC linkshare (guarantee, not cap; 8.0 has no upperlimit syntax) |
|
||
| M6 | docs complete, patchset tidy, full suite green, tagged release | **done** — docs EN+PT-BR, 11/11 suite green, tagged (v0.5.0) |
|
||
|
||
## What you get (planned)
|
||
|
||
| Area | Feature |
|
||
|---|---|
|
||
| Filtering | rules, anchors, quick, `match`/`block`(drop/return/return-rst)/`pass`, `keep state`, syncookies |
|
||
| State/Tables | stateful firewall engine, `pfr` tables (radix + hash, `pfctl -t`) |
|
||
| NAT | `nat-to` (port pools, sticky-port, static-port), `rdr-to`, `binat-to` |
|
||
| Scrub | fragment reassembly, overlap drop, `min-ttl`/`max-mss`/`df`/`no-df`, `set reassemble` |
|
||
| QoS (ALTQ successor) | `queue`/`queue on` with OpenBSD 8.0 `ifq` schedulers: **HFSC verified in the data path** (gate 15), priq default, FQ-CoDel compiled; `pfctl -s queue -v` works |
|
||
| Divert | `divert-to` / `divert` tag + `pdivert` relay over an in-module `PF_DIVERT` socket family (verified: packet to userspace and back) |
|
||
| Route | `route-to`/`dup-to`/`reply-to` + pools (`round-robin`, `source-hash`) verified (`fail-to` no longer exists in OpenBSD 8.0) |
|
||
| Logging | `pflogd` via `/dev/pflog` (DLT_PFLOG pcap, OpenBSD record layout) — verified |
|
||
| Control | `/dev/pf` (0600), OpenBSD 8.0 ioctl ABI, Linux build of `pfctl` (single binary) |
|
||
|
||
Not in scope: `pfsync`/CARP failover, IPsec/pfkey, `ftp-proxy`, per-netns PF
|
||
instances, classic-ALTQ-only schedulers (cbq/wfq/red — removed upstream before
|
||
OpenBSD 8.0).
|
||
|
||
## Screencasts
|
||
|
||
Six silent 1080p30 MP4 screencasts of the lab — implementation in the kernel,
|
||
activation, basic rules, routing, balancing and QOS — each one a real session
|
||
against the Alpine VMs:
|
||
|
||
```sh
|
||
./scripts/screencast/record-all.sh # -> out/screencast/*.mp4
|
||
```
|
||
|
||
Details, per-phase breakdown and the YouTube description text:
|
||
[`docs/en/screencast.md`](docs/en/screencast.md) ·
|
||
[`docs/pt-BR/screencast.md`](docs/pt-BR/screencast.md)
|
||
|
||
## Quick start
|
||
|
||
Full recipe: [`docs/en/install.md`](docs/en/install.md). Short version
|
||
(commands are read from the scripts; a fresh-clone end-to-end run is still
|
||
pending):
|
||
|
||
```sh
|
||
./scripts/fetch-sources.sh # OpenBSD 8.0 sources (C3SL mirror, sha256-pinned)
|
||
./scripts/vendorize.sh # stage the pristine files we port
|
||
./scripts/build-kernel.sh # kernel 7.3.4: bzImage + modules_prepare (export patch: none needed)
|
||
./scripts/build-module.sh # -> module/pf.ko
|
||
make -C tools # -> tools/out/pfctl (static), ABI harness
|
||
sudo insmod module/pf.ko # /dev/pf (0600) + netfilter hooks
|
||
sudo pfctl -f /etc/pf.conf && sudo pfctl -e
|
||
```
|
||
|
||
Read [`docs/en/pf-guide.md`](docs/en/pf-guide.md) **before** enabling PF on a
|
||
path you need: only the M2 filter core is gated today; NAT/scrub/queues/
|
||
divert/pflog are not usable yet ([`docs/en/feature-matrix.md`](docs/en/feature-matrix.md)).
|
||
|
||
VM validation lab (Alpine on libvirt): [`docs/en/vm-lab.md`](docs/en/vm-lab.md).
|
||
Documentação em português: [`README.pt-BR.md`](README.pt-BR.md) e
|
||
[`docs/pt-BR/`](docs/pt-BR/README.md).
|
||
|
||
## Layout
|
||
|
||
- `module/` — kernel sources (ported PF + compat layer; the `pfq` qdisc lands with M5)
|
||
- `tools/` — pfctl (static Linux build), pdivert relay source, ABI harness (`pflogd` not ported yet)
|
||
- `patches/kernel/` — Linux core patch set (currently empty; evidence in `p1-needs.txt`, see `docs/en/patches.md`)
|
||
- `scripts/` — fetch/build/patch/VM automation
|
||
- `tests/` — VM suite (`tests/vm/NN-*.sh`, scapy helpers)
|
||
- `docs/en/` + `docs/pt-BR/` — full bilingual documentation
|
||
- `docs/superpowers/` — design spec + implementation plan
|
||
|
||
## License
|
||
|
||
Ported OpenBSD code retains its original [ISC license and copyright notices](LICENSE).
|
||
New Linux-side code: ISC.
|