Projects#

Lua earns its place as an embedded language. The operator’s projects are usually extensions to host tools rather than stand-alone applications.

Nmap NSE script#

Write a Nmap Scripting Engine probe in Lua. NSE scripts live in /usr/share/nmap/scripts/ and are invoked with nmap --script=<name>. Write new probes when existing NSE coverage is thin.

-- nmap-scripts/operator-banner.nse
description = "Grab the HTTP server banner."
author = "operator"
license = "Same as Nmap"
categories = {"discovery", "safe"}

local shortport = require "shortport"
local http = require "http"

portrule = shortport.http

action = function(host, port)
  local resp = http.get(host, port, "/")
  return resp.header["server"] or "unknown"
end

Run.

$ nmap --script=./operator-banner.nse -p 80,443 target.example.com

Neovim plugin#

Modern Neovim is Lua-first. Plugins ship as Lua modules under lua/<name>/ and are loaded with require. The operator writes plugins to add custom commands, LSP integrations, or syntax handling.

nvim-operator/
├── README.md
└── lua/
    └── operator/
        ├── init.lua
        └── commands.lua
-- lua/operator/init.lua
local M = {}

function M.setup(opts)
  opts = opts or {}
  vim.api.nvim_create_user_command(
    "OperatorScan",
    function() require("operator.commands").scan() end,
    { nargs = 0 }
  )
end

return M

Wireshark dissector#

Custom protocol decoding inside Wireshark. Write one when reverse-engineering a private protocol on the wire.

-- ~/.config/wireshark/plugins/op.lua
local op = Proto("op", "Operator protocol")
local f_version = ProtoField.uint8("op.version", "Version")
local f_payload = ProtoField.bytes("op.payload", "Payload")
op.fields = { f_version, f_payload }

function op.dissector(buf, pkt, tree)
  pkt.cols.protocol = "OP"
  local sub = tree:add(op, buf())
  sub:add(f_version, buf(0, 1))
  sub:add(f_payload, buf(1))
end

local udp_table = DissectorTable.get("udp.port")
udp_table:add(31337, op)

Redis Lua script#

Atomic server-side scripts running inside Redis via EVAL / EVALSHA. Write these for atomic read-modify-write patterns (rate-limiters, leader election, counter-with-cap).

-- token bucket admit
local key, rate, burst, now = KEYS[1], tonumber(ARGV[1]),
                               tonumber(ARGV[2]), tonumber(ARGV[3])
local tokens = tonumber(redis.call("HGET", key, "tokens") or burst)
local last   = tonumber(redis.call("HGET", key, "last")   or now)
tokens = math.min(burst, tokens + (now - last) * rate)
local admit = tokens >= 1
if admit then tokens = tokens - 1 end
redis.call("HMSET", key, "tokens", tokens, "last", now)
return admit and 1 or 0

References#