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

A netfilter verdict — the terminal result of a rule's evaluation.

Verdicts are the kernel's per-packet decisions. The simple
verdicts (`:accept`, `:drop`, `:continue`, `:return`) take no
target; `:jump` and `:goto` target another chain by name;
`:queue` targets a userspace queue number.

## Verdict kinds

  * `:accept` — let the packet through; further chains may still
    see it.
  * `:drop` — silently drop the packet.
  * `:continue` — fall through to the next rule (the implicit
    default when no rule matches).
  * `:return` — return from the current chain (only meaningful
    inside a chain reached via `:jump`).
  * `:jump` — call into another chain; control returns when that
    chain `:return`s or runs out of rules.
  * `:goto` — tail-call another chain; control does not return.
  * `:queue` — hand the packet to a userspace queue (NFQUEUE
    consumer — `Linx.Netfilter.Queue` is deferred post-v1).

`:reject` is not a verdict — it's a statement that constructs an
ICMP/TCP-RST/ICMPX response *then* drops. Construct it via
`Linx.Netfilter.Expr.reject`.

## Construction

    iex> Verdict.accept()
    #Linx.Netfilter.Verdict<accept>

    iex> Verdict.jump("input_extras")
    #Linx.Netfilter.Verdict<jump "input_extras">

    iex> Verdict.new(:drop)
    #Linx.Netfilter.Verdict<drop>

    iex> Verdict.new({:goto, "drop_quietly"})
    #Linx.Netfilter.Verdict<goto "drop_quietly">

## Validation

`new/1` returns `{:error, {:bad_verdict, reason}}` for unknown
kinds, missing chain targets on `:jump`/`:goto`, or non-integer
queue numbers. The bang variant raises `ArgumentError`.

Wire encoding (the integer codes the kernel expects in
`NFT_DATA_VERDICT`) is handled elsewhere — this struct is pure
data.

## References

  * [`enum nft_verdicts`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/netfilter/nf_tables.h)
    — kernel's verdict integers.

# `input`

```elixir
@type input() ::
  :accept
  | :drop
  | :continue
  | :return
  | {:jump, String.t()}
  | {:goto, String.t()}
  | {:queue, non_neg_integer()}
  | t()
```

The user-facing input forms `new/1` accepts.

# `kind`

```elixir
@type kind() :: :accept | :drop | :continue | :return | :jump | :goto | :queue
```

# `t`

```elixir
@type t() :: %Linx.Netfilter.Verdict{kind: kind(), target: target()}
```

# `target`

```elixir
@type target() :: nil | String.t() | non_neg_integer()
```

# `accept`

```elixir
@spec accept() :: t()
```

Verdict: let the packet through.

# `continue`

```elixir
@spec continue() :: t()
```

Verdict: fall through to the next rule.

# `drop`

```elixir
@spec drop() :: t()
```

Verdict: silently drop the packet.

# `goto`

```elixir
@spec goto(String.t()) :: t()
```

Verdict: tail-call `chain_name`. Control does not return.

# `jump`

```elixir
@spec jump(String.t()) :: t()
```

Verdict: call into `chain_name`. Control returns when that chain
`:return`s or runs out of rules.

# `new`

```elixir
@spec new(input()) :: {:ok, t()} | {:error, {:bad_verdict, term()}}
```

Constructs a verdict from a user-friendly input form.

Accepts an atom for simple verdicts, a `{kind, target}` tuple
for parameterised verdicts, or an existing `%Verdict{}` (returned
as-is — convenient for pipeline code that doesn't know which form
it was handed).

# `new!`

```elixir
@spec new!(input()) :: t()
```

Bang variant of `new/1` — returns the verdict or raises
`ArgumentError` describing the failure.

# `queue`

```elixir
@spec queue(non_neg_integer()) :: t()
```

Verdict: hand the packet to userspace queue `num`.

# `return`

```elixir
@spec return() :: t()
```

Verdict: return from the current chain.

# `valid?`

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

Returns `true` if `v` is a well-formed verdict.

---

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