Linx.Netlink.Nfnl (Linx v0.1.0)

Copy Markdown View Source

nfnetlink (NETLINK_NETFILTER) — the kernel's netfilter-control interface: nf_tables (the modern firewall), conntrack, NFLOG, NFQUEUE.

This is the second Linx.Netlink protocol family (after Linx.Netlink.Rtnl). nfnetlink multiplexes several sub-subsystems inside one netlink family — identified by the high byte of nlmsghdr.type (subsys_id). The map (include/uapi/linux/netfilter/nfnetlink.h):

subsys_idNameLinx module
1CTNETLINKLinx.Netfilter.Conntrack (future)
3QUEUELinx.Netfilter.Queue (future)
4ULOGLinx.Netfilter.Log (NFLOG)
10NFTABLESLinx.Netfilter core
12HOOK(deferred)

Open a socket with open/1 and pass it to the appropriate higher-level module (Linx.Netfilter, eventually Linx.Netfilter.{Conntrack,Log,Queue}).

Codec helpers — nfgenmsg header encoding, subsys-id multiplexing on nlmsghdr.type, batched-transaction envelope (NFNL_MSG_BATCH_BEGIN / NFNL_MSG_BATCH_END), and the NFT_MSG_GETGEN / NEWGEN codec — live in Linx.Netlink.Nfnl.Codec. The batch/2 request engine below drives nf_tables mutating transactions on top of those primitives.

The NFTABLES sub-subsystem (id 10) is driven by Linx.Netfilter; CTNETLINK / QUEUE / HOOK are future families.

Summary

Functions

Opens an nfnetlink socket in network namespace netns.

Functions

batch(socket, inner_messages, subsys \\ :nftables, opts \\ [])

@spec batch(
  Linx.Netlink.Socket.t(),
  [Linx.Netlink.Message.t()],
  atom() | 0..255,
  keyword()
) ::
  :ok | {:error, {non_neg_integer(), Linx.Netlink.Error.t()} | term()}

Sends a batched nf_tables transaction.

Wraps inner_messages between a NFNL_MSG_BATCH_BEGIN envelope targeting subsys (default :nftables) and a NFNL_MSG_BATCH_END, assigns sequence numbers, ORs NLM_F_REQUEST | NLM_F_ACK onto every inner message, sends the whole batch in one sendmsg(2), and collects per-message ACK / error responses until every inner message has been accounted for.

Returns :ok if every inner message was accepted, or {:error, {batch_seq, %Linx.Netlink.Error{}}} for the first inner message the kernel rejected. batch_seq is the 1-indexed position of the offending message within inner_messages (the BATCH_BEGIN envelope is position 0; not returned).

The envelope messages do not themselves get ACKs from the kernel — BATCH_BEGIN merely opens the transaction, BATCH_END commits it. Per-inner-message validation errors are returned during the prep phase; commit-time failures (e.g. BATCH_GENID mismatch) surface here too, attributed to the inner message that triggered them.

Each call allocates fresh sequence numbers from the socket's counter, so concurrent users of the same socket cannot collide.

open(netns \\ :host)

@spec open(Linx.Netlink.Socket.netns()) ::
  {:ok, Linx.Netlink.Socket.t()} | {:error, term()}

Opens an nfnetlink socket in network namespace netns.

See Linx.Netlink.Socket.open/2 for the netns forms (:host, {:pid, n}, {:path, p}). Close the socket with Linx.Netlink.Socket.close/1.