Linx.Netfilter.Error exception (Linx v0.1.0)

Copy Markdown View Source

An error returned by a Linx.Netfilter operation.

Built from a failed netlink request or a rejected batch (NLMSG_ERROR reply from the kernel). The shape mirrors Linx.Mount.Error / Linx.User.Error / Linx.Sysctl.Error for :operation, :errno, :code, and :message, plus netfilter-specific context fields that are populated when the kernel surfaces them:

  • :operation — what we were trying to do, as an atom. Covers every public verb and every wire-level stage:

    • Public-API stages: :open, :close, :get_gen, :push, :pull, :diff, :subscribe, :log_listen.
    • Wire-level batch stages: :batch_begin, :batch_end, :newtable, :newchain, :newrule, :newset, :newsetelem, :newobj, :newflowtable, :delgen.
    • Namespace-acquisition stages (when opening a socket in another netns): :open_ns, :setns, :unshare, :thread.
  • :errno — the POSIX errno as an atom (:enoent, :eperm, :eacces, :einval, :erestart, :eopnotsupp, …).

  • :code — the matching positive errno integer, or nil if we don't have a mapping for this atom. Symmetric with the other Linx error structs.

  • :message — kernel's extended-ack message (NLMSGERR_ATTR_MSG), a human-readable string explaining what was wrong with the offending message. nil when the kernel didn't include one.

  • :subsys:nftables | :ctnetlink | :queue | :ulog | nil. Which nfnetlink sub-subsystem the failure was for.

  • :msg_type — the low-byte nfnetlink message type that failed, when the error came from a specific inner message (e.g. 0x06 for NFT_MSG_NEWRULE). nil for non-batch failures.

  • :batch_seq — sequence number of the offending inner message within the batch. nil for non-batch failures.

  • :attr_offset — byte offset into the offending message at which the kernel detected the problem (from NLMSGERR_ATTR_OFFS, kernel ≥ 4.12). nil when not provided.

  • :ruleset_gen — the ruleset generation at which the error occurred. Useful for ERESTART (BATCH_GENID mismatch) diagnostics. nil when not relevant.

Pattern-match on :errno and :operation to handle specific failures:

case Linx.Netfilter.push(nfnl, ruleset) do
  :ok ->
    :ok

  {:error, %Linx.Netfilter.Error{errno: :eacces}} ->
    # No CAP_NET_ADMIN; can't mutate the kernel's nftables.
    :no_perm

  {:error, %Linx.Netfilter.Error{errno: :erestart, ruleset_gen: gen}} ->
    # BATCH_GENID mismatch — another writer committed between
    # our pull and our push. Re-pull, recompute, retry.
    {:concurrent_modification, gen}

  {:error, %Linx.Netfilter.Error{errno: :eopnotsupp, msg_type: t}} ->
    # The kernel doesn't support this op on this entity —
    # typically an in-place modification that requires
    # delete+recreate.
    {:not_supported, t}
end

Implements Exception, so an error can be raised or rendered with Exception.message/1.

Caller-side input mistakes (invalid Ruleset shape, bad opts) come back as tagged tuples ({:error, {:bad_chain, _}}, {:error, {:bad_rule, _}}, {:error, {:bad_set_element, _}}, {:error, {:tag_required, _}}) — distinct from kernel rejections, matching the convention every other Linx subsystem uses.

Summary

Functions

Builds a %Linx.Netfilter.Error{} from a posix-atom errno and the operation we attempted.

Types

operation()

@type operation() ::
  :open
  | :close
  | :get_gen
  | :push
  | :pull
  | :diff
  | :subscribe
  | :log_listen
  | :batch_begin
  | :batch_end
  | :newtable
  | :newchain
  | :newrule
  | :newset
  | :newsetelem
  | :newobj
  | :newflowtable
  | :delgen
  | :open_ns
  | :setns
  | :unshare
  | :thread

subsys()

@type subsys() :: :nftables | :ctnetlink | :queue | :ulog | nil

t()

@type t() :: %Linx.Netfilter.Error{
  __exception__: true,
  attr_offset: non_neg_integer() | nil,
  batch_seq: non_neg_integer() | nil,
  code: pos_integer() | nil,
  errno: atom(),
  message: String.t() | nil,
  msg_type: 0..255 | nil,
  operation: operation(),
  ruleset_gen: non_neg_integer() | nil,
  subsys: subsys()
}

Functions

from_posix(errno, operation, opts \\ [])

@spec from_posix(atom(), operation(), keyword()) :: t()

Builds a %Linx.Netfilter.Error{} from a posix-atom errno and the operation we attempted.

Optional opts populate the netfilter-specific context fields when the caller has them (typically populated from decoded NLMSG_ERROR attributes by the request engine).