# `Linx.Netfilter.Chain`
[🔗](https://github.com/oshlabs/linx/blob/v0.2.0/lib/linx/netfilter/chain.ex#L1)

An nftables chain — a named container of rules within a table.

Chains come in two flavours:

  * **Base chains** carry a `:type` + `:hook` + `:priority` and
    (optionally) a `:policy`. The kernel attaches them to the
    hook point so packets actually flow through them.

  * **Regular chains** have none of those — they are jump/goto
    targets reachable from base chains via verdicts. Pure
    organisational tools.

## Fields

  * `:name` — chain name (unique within the table).
  * `:table` — name of the owning table; `nil` for free-standing
    chains, populated when added to a table.
  * `:type` — `:filter` | `:nat` | `:route` for base chains, `nil`
    for regular chains.
  * `:hook` — `:prerouting` | `:input` | `:forward` | `:output` |
    `:postrouting` | `:ingress` | `:egress` for base chains, `nil`
    for regular chains.
  * `:priority` — integer | atom (named priority) |
    `{atom, integer}` (named-with-offset, e.g. `{:filter, -10}`).
    Required for base chains; `nil` for regular chains.
  * `:policy` — `:accept` | `:drop`; default verdict when no rule
    matches. Only meaningful on base chains. `nil` means "no
    explicit policy" (kernel defaults to `:accept`).
  * `:device` — interface name (string). Required for `:ingress`
    and `:egress` hooks; nil otherwise.
  * `:flags` — list (advanced): `:hw_offload` enables hardware
    offload (kernel + driver permitting); other flags reserved
    for future use.
  * `:handle` — kernel-assigned handle; `nil` until pushed.
  * `:rules` — ordered list of `%Linx.Netfilter.Rule{}`.

## Validation

`new/2` validates the chain's intrinsic shape (base-vs-regular
consistency, required fields). Family-specific validation (e.g.
`:nat` type only valid in `ip`/`ip6`/`inet` families, `:ingress`
hook only valid in certain families) lives in `validate_for_family/2`
and runs when the chain is added to a table (`Linx.Netfilter.Ruleset.add_chain/4`).

## Construction

    iex> Chain.new("input", type: :filter, hook: :input, priority: 0, policy: :accept)
    {:ok, %Linx.Netfilter.Chain{name: "input", type: :filter, hook: :input, ...}}

    iex> Chain.new("ingress_drop", type: :filter, hook: :ingress, priority: -500, device: "eth0")
    {:ok, %Linx.Netfilter.Chain{hook: :ingress, device: "eth0", ...}}

    iex> Chain.new("input_extras")
    {:ok, %Linx.Netfilter.Chain{type: nil, hook: nil, ...}}  # regular chain

Errors come back as `{:error, {:bad_chain, reason}}`.

## References

  * [`enum nf_inet_hooks`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/netfilter.h)
  * [wiki.nftables.org — Configuring chains](https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains)

# `chain_type`

```elixir
@type chain_type() :: :filter | :nat | :route
```

# `hook`

```elixir
@type hook() ::
  :prerouting | :input | :forward | :output | :postrouting | :ingress | :egress
```

# `policy`

```elixir
@type policy() :: :accept | :drop
```

# `priority`

```elixir
@type priority() :: integer() | atom() | {atom(), integer()}
```

# `t`

```elixir
@type t() :: %Linx.Netfilter.Chain{
  device: String.t() | nil,
  flags: [atom()],
  handle: pos_integer() | nil,
  hook: hook() | nil,
  name: String.t(),
  policy: policy() | nil,
  priority: priority() | nil,
  rules: [Linx.Netfilter.Rule.t()],
  table: String.t() | nil,
  type: chain_type() | nil
}
```

# `add_rule`

```elixir
@spec add_rule(t(), Linx.Netfilter.Rule.t()) ::
  {:ok, t()} | {:error, {:bad_chain, term()}}
```

Returns a new chain with `rule` appended to its rules list.

This is a pure data operation — no validation beyond ensuring
`rule` is a `%Rule{}`. Higher-level validation (tag uniqueness
within chain) lives in `Linx.Netfilter.Ruleset.add_rule/4`.

The added rule's `:chain` field is set to the chain's name (so
free-standing rules pick up their context when inserted).

# `base?`

```elixir
@spec base?(t()) :: boolean()
```

Returns `true` iff `chain` is a base chain (has `:type`, `:hook`,
and `:priority` set).

# `new`

```elixir
@spec new(
  String.t(),
  keyword()
) :: {:ok, t()} | {:error, {:bad_chain, term()}}
```

Builds a chain. Validates intrinsic shape; family-specific
validation happens at `validate_for_family/2`.

# `new!`

```elixir
@spec new!(
  String.t(),
  keyword()
) :: t()
```

Bang variant of `new/2` — returns the chain or raises
`ArgumentError`.

# `validate_for_family`

```elixir
@spec validate_for_family(t(), atom()) :: :ok | {:error, {:bad_chain, term()}}
```

Validates the chain against the given family — checks family-specific
rules that `new/2` can't (since it doesn't know the family).

Rules enforced:

  * Family-allowed chain types (e.g. `:nat` invalid in `arp`,
    `bridge`, `netdev`; `:route` only in `ip`/`ip6`).
  * Family-allowed hooks (e.g. `arp` only has `:input`/`:output`;
    `netdev` only has `:ingress`/`:egress`).
  * `:nat` chains restricted to NAT-applicable hooks.
  * `:route` chains restricted to `:output` hook.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
