Linx.Netfilter.Decoder (Linx v0.1.0)

Copy Markdown View Source

Converts kernel-side %Linx.Netlink.Message{} payloads back into %Linx.Netfilter.*{} value structs.

The shape mirrors Linx.Netfilter.Encoder — one decode function per entity. from_msgs/3 groups a stream of decoded entities into a %Ruleset{}.

Wire format quirks

Same as Linx.Netfilter.Encoder: nftables NLA_U32 / NLA_U64 are big-endian, attribute IDs are namespaced.

Summary

Functions

Decodes a NEWCHAIN message body into a %Linx.Netfilter.Chain{}.

Decodes a NFNLGRP_NFTABLES multicast message into a partial %Linx.Netfilter.Event{}gen_id / proc_pid / proc_name are left nil; the Monitor GenServer fills them in from the most recent NEW_GEN event.

Builds a %Ruleset{} from separate lists of decoded entries.

Materialises a raw set-element list (from set_elements/1) into the value shape the parent set expects. Plain sets keep raw key binaries (the codec doesn't know to expand <<10, 0, 0, 5>> back to {10, 0, 0, 5} without context). Maps preserve {key, value}.

Decodes a NEWRULE message body into a %Linx.Netfilter.Rule{}.

Decodes a NEWSET body into either a %Linx.Netfilter.Set{} (plain set — no NFT_SET_F_MAP flag) or a %Linx.Netfilter.Map{} (map / vmap).

Decodes a NEWSETELEM body into a list of elements attached to a (family, table_name, set_name).

Decodes a NEWTABLE message body into a %Linx.Netfilter.Table{}.

Functions

chain(body)

Decodes a NEWCHAIN message body into a %Linx.Netfilter.Chain{}.

The chain's :family comes from the nfgenmsg header in the same message; it isn't stored on the Chain struct (it lives on the enclosing Table) but is needed here to map the wire hook number back to the family-specific hook atom.

Returns {family, chain} so the caller (typically from_msgs/3) can attach the chain to the right table.

event(message)

Decodes a NFNLGRP_NFTABLES multicast message into a partial %Linx.Netfilter.Event{}gen_id / proc_pid / proc_name are left nil; the Monitor GenServer fills them in from the most recent NEW_GEN event.

For NEW_GEN events, the gen / pid / name come from the body itself.

Dispatches on the low byte of nlmsghdr.type (the per-subsys message opcode).

from_msgs(tables, chains, rules, sets \\ [], set_elements \\ [])

Builds a %Ruleset{} from separate lists of decoded entries.

  • tables[%Table{}] from a NFT_MSG_GETTABLE dump.
  • chains[{family, %Chain{}}] from a NFT_MSG_GETCHAIN dump.
  • rules[{family, table_name, chain_name, %Rule{}}] from a NFT_MSG_GETRULE dump.
  • sets[{family, %Set{} | %Map{}}] from a NFT_MSG_GETSET dump.

  • set_elements[{family, table_name, set_name, [elem]}] from per-set NFT_MSG_GETSETELEM calls.

Chains, sets, and rules are attached to their parents by (family, table_name). Set elements are materialised against the parent set's key_type / data_type and attached to the set in dump order.

Entities that reference a missing parent are silently dropped.

materialize_elements(elements, key_type, data_type)

@spec materialize_elements([{binary(), term()} | binary()], atom(), atom() | nil) :: [
  term()
]

Materialises a raw set-element list (from set_elements/1) into the value shape the parent set expects. Plain sets keep raw key binaries (the codec doesn't know to expand <<10, 0, 0, 5>> back to {10, 0, 0, 5} without context). Maps preserve {key, value}.

rule(body)

Decodes a NEWRULE message body into a %Linx.Netfilter.Rule{}.

Returns {family, table_name, chain_name, rule} so the caller can attach to the right table+chain.

set(body)

Decodes a NEWSET body into either a %Linx.Netfilter.Set{} (plain set — no NFT_SET_F_MAP flag) or a %Linx.Netfilter.Map{} (map / vmap).

Returns {family, set_or_map} for downstream assembly.

set_elements(body)

@spec set_elements(binary()) ::
  {Linx.Netfilter.Table.family(), String.t(), String.t(),
   [{binary(), term()} | binary()]}

Decodes a NEWSETELEM body into a list of elements attached to a (family, table_name, set_name).

Returns {family, table_name, set_name, elements} where elements is a list of either raw key terms or {key, value} tuples (the caller resolves which based on whether the parent set is plain or a map).

For now we return the elements with KEY binary unparsed (raw binary) and DATA either a raw binary or a %Verdict{} for verdict data. Higher-level conversion (binary → tuple, etc.) happens at assembly time when we know the parent set's key_type.

table(body)

@spec table(binary()) :: Linx.Netfilter.Table.t()

Decodes a NEWTABLE message body into a %Linx.Netfilter.Table{}.

body is %Message{payload: body}'s payload — nfgenmsg header followed by NLAs.