--- /dev/null
+# Test Description
+
+Test the `suricata.ntp` Lua library from a Lua output script.
+
+## PCAP
+
+Reuses `tests/ntp-keywords/input.pcap`, generated by
+`tests/ntp-keywords/generate-pcap.py`.
--- /dev/null
+NTP version=4 mode=3 stratum=0 reference_id=00:00:00:00
+NTP version=4 mode=4 stratum=2 reference_id=4c:4f:43:4c
+NTP version=3 mode=3 stratum=0 reference_id=00:00:00:00
+NTP version=3 mode=4 stratum=2 reference_id=4c:4f:43:4c
--- /dev/null
+local ntp = require("suricata.ntp")
+local config = require("suricata.config")
+local logger = require("suricata.log")
+
+local filename = "lua-ntp.log"
+
+local function to_hex(bytes)
+ local parts = {}
+ for i = 1, #bytes do
+ parts[#parts + 1] = string.format("%02x", string.byte(bytes, i))
+ end
+ return table.concat(parts, ":")
+end
+
+function init(args)
+ local needs = {}
+ needs["protocol"] = "ntp"
+ return needs
+end
+
+function setup(args)
+ logger.notice("lua: setup()")
+ file = assert(io.open(config.log_path() .. "/" .. filename, "w"))
+end
+
+function log(args)
+ local tx, err = ntp.get_tx()
+ if tx == nil then
+ print(err)
+ return
+ end
+
+ local msg = string.format("NTP version=%d mode=%d stratum=%d reference_id=%s",
+ tx:version(), tx:mode(), tx:stratum(), to_hex(tx:reference_id()))
+ write(msg)
+end
+
+function deinit(args)
+ file:close(file)
+end
+
+function write(msg)
+ file:write(msg .. "\n")
+end
--- /dev/null
+%YAML 1.1
+---
+
+outputs:
+ - lua:
+ enabled: yes
+ scripts-dir: .
+ scripts:
+ - output.lua
--- /dev/null
+requires:
+ min-version: 9
+
+pcap: ../../ntp-keywords/input.pcap
+
+args:
+ - --runmode=single
+
+checks:
+ - file-compare:
+ filename: lua-ntp.log
+ expected: expected/lua-ntp.log
--- /dev/null
+# Test Description
+
+Test the `suricata.ntp` Lua library from detection rules.
+
+## PCAP
+
+Reuses `tests/ntp-keywords/input.pcap`, generated by
+`tests/ntp-keywords/generate-pcap.py`.
--- /dev/null
+local ntp = require("suricata.ntp")
+
+function init(args)
+ return {}
+end
+
+function match(args)
+ local tx, err = ntp.get_tx()
+ if tx == nil then
+ print(err)
+ return 0
+ end
+
+ if tx:version() == 4 and tx:mode() == 4 and tx:stratum() == 0 then
+ return 1
+ end
+
+ return 0
+end
--- /dev/null
+local ntp = require("suricata.ntp")
+
+function init(args)
+ return {}
+end
+
+function match(args)
+ local tx, err = ntp.get_tx()
+ if tx == nil then
+ print(err)
+ return 0
+ end
+
+ if tx:version() == 3 and tx:mode() == 4 and tx:stratum() == 2 and
+ tx:reference_id() == "\x4c\x4f\x43\x4c" then
+ return 1
+ end
+
+ return 0
+end
--- /dev/null
+local ntp = require("suricata.ntp")
+
+function init(args)
+ return {}
+end
+
+function match(args)
+ local tx, err = ntp.get_tx()
+ if tx == nil then
+ print(err)
+ return 0
+ end
+
+ if tx:version() == 4 and tx:mode() == 3 and tx:stratum() == 0 and
+ tx:reference_id() == "\0\0\0\0" then
+ return 1
+ end
+
+ return 0
+end
--- /dev/null
+alert ntp any any -> any any (msg:"TEST NTP LUA v4"; ntp.version:>=3; lua:test-v4.lua; sid:1; rev:1;)
+alert ntp any any -> any any (msg:"TEST NTP LUA v3"; ntp.version:>=3; lua:test-v3.lua; sid:2; rev:1;)
+alert ntp any any -> any any (msg:"TEST NTP LUA no match"; ntp.version:>=3; lua:test-no-match.lua; sid:3; rev:1;)
--- /dev/null
+pcap: ../../ntp-keywords/input.pcap
+
+requires:
+ min-version: 9
+
+args:
+ - --set default-rule-path=${TEST_DIR}
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 2
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 3