Lunatik

netfilterModule

Lua interface to the Linux Netfilter framework.

A script that registers hooks runs in a softirq runtime, lunatik run -c softirq <script>; see execution contexts. Hooks are registered in the initial network namespace only: packets of another namespace do not reach them.

Usage

-- lunatik run -c softirq <script>: drops the locally generated IPv4 packets marked 0x10,
-- as `sudo ping -m 16 127.0.0.1` sends them
local netfilter = require("netfilter")
local nf        = require("linux.nf")

local MARK <const> = 0x10

local function drop(skb)
  return nf.action.DROP
end

netfilter.register{
  hook     = drop,
  pf       = nf.proto.IPV4,
  hooknum  = nf.inet.LOCAL_OUT,
  priority = nf.ip.pri.FILTER,
  mark     = MARK,
}

Class netfilter_hook

netfilter_hook:stop () Stops the hook’s callback.

netfilter

register (opts) Registers a Netfilter hook.

Class netfilter_hook in detail

A registered Netfilter hook. Returned by netfilter.register.
netfilter_hook:stop ()
Stops the hook’s callback. A packet the hook sees afterwards takes the ACCEPT policy without reaching Lua. The hook stays registered until the runtime closes, since unregistering it sleeps and a stop may come from a callback; in a percpu script this stops the callback of this runtime alone. Calling it again does nothing, and a to-be-closed variable holding the hook stops it the same way.

Returns

    nil

Usage

hook:stop()

netfilter in detail

register (opts)
Registers a Netfilter hook. In a percpu script the runtimes share one hook: the first registration installs it, the others attach their callbacks, and a packet reaches the runtime of the CPU it arrived on.

Parameters

  • opts table Hook options: hook (function), pf, hooknum, priority (integers), and optionally mark (integer), a prefilter that keeps a packet out of Lua: given a mark, 0 included, only a packet whose skb:mark() equals it reaches the callback, and the hook accepts every other packet; without a mark, the callback runs for every packet. pf takes a linux.nf.proto value, hooknum a hook of that family, as linux.nf.inet, linux.nf.arp or linux.nf.br list them, and priority a linux.nf.ip.pri or linux.nf.br.pri value.

    hook(skb) returns the packet’s verdict, DROP, ACCEPT or QUEUE of linux.nf.action, and optionally a mark to set on the packet. A callback that returns no verdict, or that raises, accepts the packet; one that returns any other value, STOLEN, REPEAT and STOP included, accepts it too and logs invalid verdict. A mark that is not an integer from 0 to 232 - 1 leaves the packet’s mark as it was and logs invalid mark.

Returns

    netfilter_hook the hook, which netfilter.register keeps for its runtime: dropping it stops nothing, and the callback runs until stop or the end of the runtime. The hook stays registered until the runtime closes, and the one hook a percpu script’s runtimes share until the percpu set stops.

Raises

“not allowed once the runtime is armed” past the script body; runtime context mismatch outside a softirq runtime; not allowed while the runtime closes from a finalizer that runs at its close; bad field 'hook' (function expected, got <type>) if hook is missing or not a function; bad field '<field>' (number expected, got <type>) if pf, hooknum or priority is missing or not a number, or if mark is present and not a number; bad field '<field>' (out of bounds) if pf is not a family whose hooks netfilter keeps in a table, hooknum is not a hook of that table, mark is negative or past 32 bits, or priority is past an int; if the hook cannot be registered; in a percpu script, if this runtime already registered the same pf, hooknum, priority and mark, or the same three both times without a mark

Usage

local netfilter = require("netfilter")
local nf        = require("linux.nf")

local QUARANTINED <const> = 2 -- ifindex

local function quarantine(skb)
  return skb:ifindex() == QUARANTINED and nf.action.DROP or nf.action.ACCEPT
end

netfilter.register{
  hook     = quarantine,
  pf       = nf.proto.INET,
  hooknum  = nf.inet.PRE_ROUTING,
  priority = nf.ip.pri.FILTER,
}