Replicating BSD authpf(8) semantics via nftables verdict maps
[email protected] Wed, 18 Mar 2026 14:39:07 +0530
| Newsgroups | gmane.comp.security.firewalls.netfilter.general |
|---|---|
| Message-ID | <[email protected]> |
Hi,
I=E2=80=99m attempting to replicate OpenBSD=E2=80=99s authpf(8) behaviour o=
n Arch
linux. My current approach feels slightly "bolted on," and I=E2=80=99d
appreciate a sanity check on the architecture before I commit.
The Objective: SSH triggered, per-session firewalling without a shell.
Login should atomically provision network access, logout must tear it
down.
I=E2=80=99m using a verdict map to dispatch traffic to dynamic, session-
specific chains based on packet marks.
table inet authnft {
map session_dispatch {
type mark : verdict
}
chain input {
type filter hook input priority 0; policy drop;
meta mark vmap @session_dispatch
}
chain ssh_session_ID {
# Session-specific rules here
}
}
On login (via small userspace helper):
- Allocate a per-session mark
- Create a dynamic chain, and batch insert the mark -> jump entry into
the map
Logout (via same helper):
- Delete the map entry and the associated chain (systemd calls our
binary, provides the slice details).
Some of things I am not clear about:
1. Does an nft batch guarantee I won=E2=80=99t hit a "missing chain" during=
a
concurrent map update?
2. Is meta mark the right tool here, or should I be looking at meta
cgroup to tie this more tightly to the systemd scope?
3. Any pitfalls to be aware of when managing ~1000 dynamic chains / map
entries?
4. Is this a sensible use of nftables, or is this firmly in the "just
use eBPF" category?
If the answer is =E2=80=9Cthis is cursed, do X instead=E2=80=9D, I=E2=80=99=
d appreciate the
correction.
Cheers,
Avi