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