104 lines
6.9 KiB
Markdown
104 lines
6.9 KiB
Markdown
# Guia de arquitetura — uma página
|
||
|
||
English: [docs/en/guide.md](../en/guide.md).
|
||
|
||
## O que este port é
|
||
|
||
Um port fiel do **engine PF do OpenBSD 8.0** rodando dentro do **Linux
|
||
7.3.4** como um único módulo out-of-tree, `pf.ko`. Nada é simulado: o
|
||
casamento de regras, estado, tabelas, normalização e filas *é* o código do
|
||
OpenBSD, compilado sob uma camada de compatibilidade; o controle vem do
|
||
`pfctl` real, falando a ABI ioctl OpenBSD de verdade por `/dev/pf`. Existe
|
||
**uma instância global do PF, presa a `init_net`** — exatamente como o
|
||
OpenBSD tem um único kernel; instâncias por netns estão fora de escopo.
|
||
|
||
Alvos de build: fontes OpenBSD 8.0 (sha256 fixado em `VERSIONS`), Linux
|
||
7.3.4 (`linux-7.3.4`), `gcc >= 15`, bison. O `pfvar.h` v1.548 é compartilhado
|
||
bit a bit entre kernel e userland (codificação de ioctl em
|
||
`module/include/pfk.h`).
|
||
|
||
## Componentes
|
||
|
||
| Caminho | Papel |
|
||
|---|---|
|
||
| `module/pfsrc/` | Arquivos portados do OpenBSD: `pf.c` (engine), `pf_ioctl.c` (ABI DIOC*), `pf_norm.c` (scrub/fragmentos), `pf_table.c`, `pf_ruleset.c`, `pf_if.c`, `pf_lb.c` (pools/portas NAT), `pf_osfp.c`, `pf_syncookies.c`, `ifq.c`/`hfsc.c`/`fq_codel.c` (staged para M5), `if_pflog.c` + `ip_divert.c` (referências staged), `divert_sock.c` (stub de entrada do divert), `pfk_mod.c` (load/exit, `/dev/pf`), `pfk_hooks.c` (caminho de dados netfilter) |
|
||
| `module/compat/` | Infra Linux sob os fontes em forma BSD: shim mbuf-sobre-`sk_buff` (`pfk_mbuf`), glue de kernel (malloc/pools/timeouts/locks, `pfk_kern`), visão de interfaces e endereços (`pfk_if`), saída/forward IP com semântica BSD (`pfk_ip4`, `pfk_ip6`), busca de sockets (`pfk_pcb`), API ifq com semântica priq (`pfk_ifq`), radix/rotas/crypto portados |
|
||
| `module/include/` | `pfk.h` (header mestre da compat + codificação `_IO*` estilo OpenBSD), `net/pfvar.h` staged, `pfk_mbuf.h`, `pfk_net.h`, `pfk_if.h` |
|
||
| `tools/` | Build Linux do `pfctl` do OpenBSD 8.0 (binário único), relay `pdivert`, verificador de ABI (`abitest` + `make abi`), testes de parse offline (`make test`). Deltas vs upstream: `tools/UPSTREAM.md` |
|
||
| `scripts/` | `fetch-sources.sh`, `vendorize.sh`, `stage-port.sh` (staging determinístico), `build-kernel.sh`, `build-module.sh`, automação da bancada `vm-*.sh` |
|
||
| `tests/vm/` | Gates da suíte em VM: `01-state.sh … 04-anchors.sh` + `lib.sh`; `tests/confs/` com rulesets deployados na bancada |
|
||
| `patches/kernel/` | Conjunto de patches de core — hoje **vazio** (`p1-needs.txt` registra por que nenhum export foi necessário); ver [patches.md](patches.md) |
|
||
|
||
## Caminho de dados (M2, como implementado hoje)
|
||
|
||
O OpenBSD roda o PF em `IPL_NET`, em contexto de processo; nossas locks da
|
||
compat são sleepáveis, então o hook **nunca chama `pf_test()` em softirq**. O
|
||
pacote é furtado (`NF_STOLEN`) para uma workqueue ordenada (`pfk_netisr`), o
|
||
veredito roda em contexto de processo e é aplicado por **reinjeção**, com
|
||
marcação por direção em `skb->mark` para que o pacotão sobrevivente não seja
|
||
re-enfileirado pelo nosso próprio hook.
|
||
|
||
```
|
||
Linux 7.3.4, módulo pf.ko
|
||
NIC ──► netfilter (softirq — apenas enfileira)
|
||
PRE_ROUTING PF_IN ─┐ ┌─ LOCAL_OUT PF_OUT
|
||
POST_ROUTING PF_OUT ─┤ NF_STOLEN ├─ (roda DEPOIS do conntrack)
|
||
LOCAL_IN/FORWARD: pass-through ┘ POST_ROUTING: NF_IP_PRI_LAST-1
|
||
│ (ref da skb + kmalloc pfk_pkt;
|
||
│ falha de alocação ⇒ NF_ACCEPT = fail-open)
|
||
▼
|
||
workqueue pfk_netisr (contexto de processo)
|
||
│
|
||
pfk_m_wrap_skb(skb)──► shim struct mbuf
|
||
│
|
||
pf_test(af, dir, ifp, &m) ◄── o engine real do OpenBSD 8.0:
|
||
│ scrub/normalize → lookup de estado
|
||
│ → regras/anchors/tabelas/quick
|
||
│ → inserção de estado → veredito
|
||
▼
|
||
pass ──► mark |= PFK_DONE_IN/OUT ──► reinjeta: PF_IN: netif_rx() (sobrevivente
|
||
da remontagem entra no stack)
|
||
PF_OUT: skb_dst()->output()
|
||
block/drop ──► kfree_skb() (+ RST/ICMP de retorno gerados pelo próprio PF)
|
||
fragmento em buffer ──► nossa ref é liberada; pf mantém o sobrevivente (m == NULL)
|
||
```
|
||
|
||
Plano de controle: `/dev/pf` (miscdev, modo 0600, escrita condicionada a
|
||
`CAP_NET_ADMIN`) → `pfk_ioctl_io()` copia a estrutura de parâmetros usando o
|
||
tamanho embutido na codificação `_IOR/_IOW` OpenBSD e despacha para o
|
||
`pfioctl()` portado (`pf_ioctl.c`) — a ABI DIOC* completa, como upstream.
|
||
`pfctl -e/-f/-s/-t` é o mesmo binário do OpenBSD, recompilado.
|
||
|
||
## Filas, divert, pflog — comportamento observável hoje
|
||
|
||
- **Filas**: o `pfctl` faz o parse de `queue`/`queue on` (sintaxe 8.0); no
|
||
kernel a API ifq é implementada por `compat/pfk_ifq.c` com **semântica
|
||
priq apenas**; o qdisc classful `pfq` e os back ends HFSC/FQ-CoDel chegam
|
||
em **M5**. `ifq.c`/`hfsc.c`/`fq_codel.c` estão staged e prontos para
|
||
compilar, mas ainda **não** estão na lista de objetos do módulo.
|
||
- **Divert**: `divert-to`/tag `divert` produzem o veredito `PF_DIVERT` do PF;
|
||
`divert_packet()` (`pfsrc/divert_sock.c`) hoje **descarta o pacote com um
|
||
`pr_warn` rate-limited**, porque a família de sockets AF_DIVERT ainda não
|
||
foi instanciada. O relay userspace `pdivert` existe e espera
|
||
`socket(PF_DIVERT=32, SOCK_RAW, IPPROTO_DIVERT=254)`.
|
||
- **pflog**: `pflog_packet()` retorna sucesso mas **não loga nada** (um
|
||
único `pr_warn "packet not logged"`); `if_pflog.c` está staged, back end
|
||
netlink em M4/M5.
|
||
|
||
## Milestones (status por feature em feature-matrix.md)
|
||
|
||
| Milestone | Escopo | Status (2026-11-11) |
|
||
|---|---|---|
|
||
| M0 | repo, scripts, build do kernel, VM liga com kernel próprio | concluído |
|
||
| M1 | camada de compat, `pf.ko` carrega, `/dev/pf`, `pfctl -f`/`-s info` | concluído |
|
||
| M2 | núcleo do filtro: regras/estados/tabelas/âncoras, gates VM | **pronto** — gates 01–04 verdes |
|
||
| M3 | NAT (`nat-to`/`rdr-to`/`binat-to`), scrub, pflog | **pronto** — gates 05/06/07/09 (incl. integridade de 2 MB via redirect) e pflog gate 12 |
|
||
| M4 | route-to/dup-to/reply-to, pools, divert e2e | **pronto** — gates 08/10/13 e divert gate 11 |
|
||
| M5 | filas: back ends ifq (hfsc/fq_codel) + qdisc `pfq` | pendente (código dos escalonadores portado, qdisc faltando) |
|
||
| M6 | docs completas, patchset limpo, suíte verde, releases com tag | em andamento — docs EN+PT-BR completas, suíte 14/14 verde, com tag |
|
||
|
||
## Próximas leituras
|
||
|
||
[build.md](build.md) → [vm-lab.md](vm-lab.md) → [pf-guide.md](pf-guide.md) →
|
||
[feature-matrix.md](feature-matrix.md) → [caveats.md](caveats.md).
|