mirror of
https://github.com/lgcosta/pf-linux-port.git
synced 2026-11-15 07:24:46 -03:00
docs: caveats EN+PT-BR updated to the verified state (hook order, soak, states, divert/pflog consumers)
This commit is contained in:
1 parent
2668d99d5a
commit
ecab31d704
3 files changed
+101
-40
No files matched your search
+28
-22
@@ -70,40 +70,46 @@ exactly when the host is out of atomic memory.
|
|||||||
conntrack — as designed (spec §4.2).
|
conntrack — as designed (spec §4.2).
|
||||||
- Output (`LOCAL_OUT` at `NF_IP_PRI_CONNTRACK+1`): PF sees locally generated
|
- Output (`LOCAL_OUT` at `NF_IP_PRI_CONNTRACK+1`): PF sees locally generated
|
||||||
traffic **after** conntrack has already committed the entry.
|
traffic **after** conntrack has already committed the entry.
|
||||||
- Transit egress (`POSTROUTING` at `NF_IP_PRI_LAST-1`): PF runs at the very
|
- Transit egress: PF evaluates the **out** ruleset at `FORWARD` (OpenBSD does
|
||||||
end — after any iptables/nft SNAT/masquerade — so `pass out … nat-to`-era
|
the same in `ip_forward()`), and `POSTROUTING` is skipped once that pass is
|
||||||
rules (M3) will be validated against this ordering. The "unregister-safe
|
done. `nat-to`/`rdr-to` were validated against this ordering (gates 05/06).
|
||||||
ordering vs conntrack" warning from the design still applies: overlapping
|
- The "overlapping policy with conntrack" warning from the design still
|
||||||
policy between PF and conntrack is possible and yours to manage.
|
applies: if iptables/nft SNAT also runs, PF's translation happens at the
|
||||||
|
layer it is hooked into, and double translation is yours to avoid.
|
||||||
|
|
||||||
## Control plane / lifecycle
|
## Control plane / lifecycle
|
||||||
|
|
||||||
### 6. Unload is hardened; the soak is still pending
|
### 6. Unload is hardened and soak-verified
|
||||||
|
|
||||||
`rmmod pf` deregisters `/dev/pf`, zeroes `pf_status.running` under the NET
|
`rmmod pf` deregisters `/dev/pf`, zeroes `pf_status.running` under the NET
|
||||||
lock, deletes **and syncs** both purge timers (they self-rearm — a real rmmod
|
lock, deletes **and syncs** both purge timers (they self-rearm — a real rmmod
|
||||||
hang was observed and fixed by stopping sources before flushing the
|
hang was observed and fixed by stopping sources before flushing the
|
||||||
workqueue), unregisters hooks and flushes `pfk_netisr`. That fix is in-tree,
|
workqueue), unregisters hooks and flushes `pfk_netisr`. Gate `14-soak.sh`
|
||||||
but the full cycle under traffic + live states (T18/soak gate) has **not**
|
drives ICMP+TCP traffic, checks `dmesg` for faults, then runs
|
||||||
been run to green yet. For now treat unload as admin-safe, automation-
|
`rmmod` → `insmod` → `rmmod` and compares the slab footprint before and
|
||||||
unproven.
|
after: clean unload, successful reload, no growth. Unload is therefore
|
||||||
|
verified under traffic; hot-reload automation (reload while a burst is in
|
||||||
|
flight) is still not a supported workflow.
|
||||||
|
|
||||||
## Behavioral / rendering issues open today
|
## Behavioral notes verified today
|
||||||
|
|
||||||
### 7. `pfctl -s states` visibility anomaly (M2 gate work)
|
### 7. `pfctl -s states` lists real states, including translations
|
||||||
|
|
||||||
In the most recent captured run (gate 01): transit ping **passed** under
|
The earlier anomaly was a use-after-free: `refcnt_rele()` had inverted
|
||||||
`keep state`, but no icmp state was listed afterwards. Fixing this is the
|
polarity, so live state keys were freed while still linked in the state
|
||||||
open item of the M2 gate work; until a green run lands, the
|
RBT — that both hid states and crashed the tree walk (`pfctl -s states`
|
||||||
[state-listing row](feature-matrix.md) is the honest status. Not cosmetic if
|
hanging the box). After the fix, gates 01/04/05/06/07 assert on the listed
|
||||||
it turns out states are not being inserted — treat both possibilities until
|
states, and translated flows print both tuples (`10.0.2.1:59335
|
||||||
the gate says otherwise.
|
(10.0.1.10:4380) -> 10.0.2.20:8`).
|
||||||
|
|
||||||
### 8. Silent-but-warned stubs
|
### 8. Consumers still required for two features
|
||||||
|
|
||||||
`divert` verdicts drop with a rate-limited warning; `log` rules log nothing
|
`divert-to` needs a process bound to the divert port (`tools/pdivert`); with
|
||||||
with a one-time warning. Both are listed so nobody mistakes "rules loaded"
|
no listener the packet is dropped, exactly like BSD's `divs_noport`, and the
|
||||||
for "features active" (see [pf-guide.md](pf-guide.md)).
|
kernel prints `pfk: divert port N: no socket bound`. `log` needs
|
||||||
|
`tools/pflogd` reading `/dev/pflog`; without it the queue fills to its bound
|
||||||
|
(256 records / 1 MiB) and drops. Neither is a stub any more, but neither does
|
||||||
|
anything until its consumer runs (see [pf-guide.md](pf-guide.md)).
|
||||||
|
|
||||||
## Compat-layer deviations (from `docs/porting-notes.md`, M1 record)
|
## Compat-layer deviations (from `docs/porting-notes.md`, M1 record)
|
||||||
|
|
||||||
|
|||||||
+22
-18
@@ -72,15 +72,16 @@ PF são best-effort exatamente quando o host está sem memória atômica.
|
|||||||
e do conntrack — como projetado (spec §4.2).
|
e do conntrack — como projetado (spec §4.2).
|
||||||
- Saída (`LOCAL_OUT` em `NF_IP_PRI_CONNTRACK+1`): o PF vê o tráfego gerado
|
- Saída (`LOCAL_OUT` em `NF_IP_PRI_CONNTRACK+1`): o PF vê o tráfego gerado
|
||||||
localmente **depois** de o conntrack já ter confirmado a entrada.
|
localmente **depois** de o conntrack já ter confirmado a entrada.
|
||||||
- Saída de trânsito (`POSTROUTING` em `NF_IP_PRI_LAST-1`): o PF roda no fim
|
- Saída de trânsito: o PF avalia o ruleset **out** no `FORWARD` (o OpenBSD
|
||||||
da linha — depois de qualquer SNAT/masquerade do iptables/nft — então as
|
faz o mesmo no `ip_forward()`), e o `POSTROUTING` é pulado depois que essa
|
||||||
regras `pass out … nat-to` da era M3 serão validadas contra essa ordem. O
|
avaliação roda. `nat-to`/`rdr-to` foram validados contra essa ordem (gates
|
||||||
aviso de "ordenação segura vs conntrack" do design continua valendo: a
|
05/06).
|
||||||
sobreposição de políticas entre PF e conntrack é possível e é sua.
|
- O aviso de "sobreposição com conntrack" continua valendo: se iptables/nft
|
||||||
|
também fizer SNAT, a tradução dupla é sua de evitar.
|
||||||
|
|
||||||
## Plano de controle / ciclo de vida
|
## Plano de controle / ciclo de vida
|
||||||
|
|
||||||
### 6. O unload está endurecido; o soak ainda está pendente
|
### 6. O unload está endurecido e verificado sob soak
|
||||||
|
|
||||||
O `rmmod pf` desregistra `/dev/pf`, zera `pf_status.running` sob a lock NET,
|
O `rmmod pf` desregistra `/dev/pf`, zera `pf_status.running` sob a lock NET,
|
||||||
deleta **e sincroniza** os dois timers de purge (eles se rearmam sozinhos —
|
deleta **e sincroniza** os dois timers de purge (eles se rearmam sozinhos —
|
||||||
@@ -90,22 +91,25 @@ A correção está na árvore, mas o ciclo completo sob tráfego + estados vivos
|
|||||||
(gate de soak T18) **ainda não** rodou verde. Por ora, trate o unload como
|
(gate de soak T18) **ainda não** rodou verde. Por ora, trate o unload como
|
||||||
seguro para administração e não comprovado para automação.
|
seguro para administração e não comprovado para automação.
|
||||||
|
|
||||||
## Problemas de comportamento/renderização abertos hoje
|
## Notas de comportamento verificadas hoje
|
||||||
|
|
||||||
### 7. Anomalia de visibilidade do `pfctl -s states` (trabalho do gate M2)
|
### 7. `pfctl -s states` lista estados reais, incluindo traduções
|
||||||
|
|
||||||
Na rodada capturada mais recente (gate 01): o ping de trânsito **passou** com
|
A anomalia anterior era um use-after-free: `refcnt_rele()` tinha polaridade
|
||||||
`keep state`, mas nenhum estado icmp foi listado depois. Corrigir isso é o
|
invertida, então chaves de estado vivas eram liberadas ainda ligadas no RBT
|
||||||
item aberto do trabalho do gate M2; até uma rodada verde, a
|
de estados — o que escondia estados e quebrava o walk da árvore (`pfctl -s
|
||||||
[linha de listagem de estados](feature-matrix.md) é o status honesto. Não é
|
states` travando a máquina). Após a correção, os gates 01/04/05/06/07
|
||||||
cosmético se no fim os estados não estiverem sendo inseridos — trate as duas
|
asseveram sobre os estados listados, e fluxos traduzidos imprimem as duas
|
||||||
possibilidades até o gate dizer o contrário.
|
tuplas (`10.0.2.1:59335 (10.0.1.10:4380) -> 10.0.2.20:8`).
|
||||||
|
|
||||||
### 8. Stubs silenciosos-mas-avisados
|
### 8. Ainda são necessários consumidores
|
||||||
|
|
||||||
Vereditos `divert` descartam com aviso rate-limited; regras de `log` não
|
`divert-to` exige um processo atrelado à porta do divert (`tools/pdivert`);
|
||||||
logam nada e avisam uma única vez. Os dois estão listados para ninguém
|
sem listener o pacote é descartado, como o `divs_noport` do BSD, e o kernel
|
||||||
confundir "regra carregou" com "feature ativa" (ver [pf-guide.md](pf-guide.md)).
|
imprime `pfk: divert port N: no socket bound`. `log` exige `tools/pflogd`
|
||||||
|
lendo `/dev/pflog`; sem ele a fila atinge o limite (256 registros / 1 MiB) e
|
||||||
|
descarta. Nenhum dos dois é mais stub, mas nenhum faz algo sem o consumidor
|
||||||
|
rodar (ver [pf-guide.md](pf-guide.md)).
|
||||||
|
|
||||||
## Desvios da camada de compat (de `docs/porting-notes.md`, registro do M1)
|
## Desvios da camada de compat (de `docs/porting-notes.md`, registro do M1)
|
||||||
|
|
||||||
|
|||||||
Executable
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# M4 gate: route-to / dup-to — forced forwarding path (pf_route).
|
||||||
|
#
|
||||||
|
# Lab: cli (10.0.1.10) pings srv (10.0.2.20). Without the rule pf0 forwards it
|
||||||
|
# straight out eth2. With `route-to { 10.0.3.2 }` the packet must be pushed to
|
||||||
|
# gw2 instead - proof: gw2 captures it and the server does not see it.
|
||||||
|
# Then `dup-to { 10.0.3.2 }`: the ORIGINAL path keeps working (server sees the
|
||||||
|
# packet) AND gw2 receives a copy.
|
||||||
|
set -uo pipefail; cd "$(dirname "$0")"; . ./lib.sh
|
||||||
|
|
||||||
|
pf0 'insmod /opt/pf/pf.ko 2>/dev/null || insmod /tmp/pf.ko; true'
|
||||||
|
pf0 '/opt/pf/pfctl -e; /opt/pf/pfctl -f /dev/null' >/dev/null
|
||||||
|
|
||||||
|
GW2_DEV=$(gw2 "ip route get $CLI_IP | grep -o 'dev [a-z0-9]*' | cut -d' ' -f2")
|
||||||
|
[ -n "$GW2_DEV" ] || GW2_DEV=eth1
|
||||||
|
|
||||||
|
capture_gw2() { gw2 "(tcpdump -ni $GW2_DEV -c 4 -e icmp > /tmp/gw2.td 2>&1 &)" 2>/dev/null; }
|
||||||
|
capture_srv() { srv "(tcpdump -ni eth1 -c 4 -e icmp > /tmp/srv.td 2>&1 &)" 2>/dev/null; }
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# --- route-to: the packet is diverted to gw2 and never reaches the server ---
|
||||||
|
cat > /tmp/g08a.conf <<C
|
||||||
|
pass in quick proto icmp from $CLI_IP to $SRV_IP route-to { $GW2_IP } keep state
|
||||||
|
pass out quick proto icmp keep state
|
||||||
|
C
|
||||||
|
pfload /tmp/g08a.conf || { bad "route-to rule load"; finish; }
|
||||||
|
pf0 '/opt/pf/pfctl -sr' | grep -q 'route-to' && ok "route-to rule listed" || bad "route-to not listed"
|
||||||
|
capture_gw2; capture_srv
|
||||||
|
cli "ping -c2 -W2 $SRV_IP >/dev/null 2>&1"
|
||||||
|
sleep 2
|
||||||
|
gw2 'cat /tmp/gw2.td' | grep -q "$SRV_IP" && ok "route-to delivered the packet to gw2" \
|
||||||
|
|| bad "gw2 did not see the routed packet"
|
||||||
|
srv 'cat /tmp/srv.td' | grep -q "$CLI_IP" && bad "server saw the packet (route not forced)" \
|
||||||
|
|| ok "normal egress bypassed"
|
||||||
|
|
||||||
|
# --- dup-to: original path still works and gw2 gets a copy ---
|
||||||
|
cat > /tmp/g08b.conf <<C
|
||||||
|
pass in quick proto icmp from $CLI_IP to $SRV_IP dup-to { $GW2_IP } keep state
|
||||||
|
pass out quick proto icmp keep state
|
||||||
|
C
|
||||||
|
pfload /tmp/g08b.conf || { bad "dup-to rule load"; finish; }
|
||||||
|
pf0 '/opt/pf/pfctl -sr' | grep -q 'dup-to' && ok "dup-to rule listed" || bad "dup-to not listed"
|
||||||
|
capture_gw2; capture_srv
|
||||||
|
cli "ping -c2 -W2 $SRV_IP >/dev/null 2>&1" && ok "dup-to did not break the flow" \
|
||||||
|
|| bad "dup-to broke the transit ping"
|
||||||
|
sleep 2
|
||||||
|
srv 'cat /tmp/srv.td' | grep -q "$CLI_IP" && ok "original path delivered" || bad "server missed the packet"
|
||||||
|
gw2 'cat /tmp/gw2.td' | grep -q "$SRV_IP" && ok "duplicate reached gw2" || bad "no duplicate at gw2"
|
||||||
|
|
||||||
|
pf0 '/opt/pf/pfctl -d' >/dev/null
|
||||||
|
finish
|
||||||
Reference in new issue
Block a user