#!/usr/bin/env lua local ubus = require "ubus" local fs = require "nixio.fs" local conn = ubus.connect() if not conn then error("Failed to connect to ubus") return end local args = "-n" local duration = "" local workdir = "/var/run/packet_capture" local filterfile = workdir .. "/tcpdump_filter" local pcapbase = workdir .. "/capture.pcap" local outputfile = "/tmp/capture.pcap" local function validate_args(value) if type(value) ~= "string" or value == "" then return false end local tokens = {} for token in value:gmatch("%S+") do tokens[#tokens + 1] = token end local i = 1 while i <= #tokens do local token = tokens[i] if token == "-n" or token == "-e" then i = i + 1 elseif token == "-i" then if not tokens[i + 1] or not tokens[i + 1]:match("^[%w_.:-]+$") then return false end i = i + 2 elseif token == "-c" then if not tokens[i + 1] or not tokens[i + 1]:match("^%d+$") then return false end i = i + 2 elseif token == "-W" then if tokens[i + 1] ~= "2" then return false end i = i + 2 elseif token == "-C" then if not tokens[i + 1] or not tokens[i + 1]:match("^%d+$") then return false end i = i + 2 elseif token == "-w" then if tokens[i + 1] ~= pcapbase then return false end i = i + 2 elseif token == "-z" then if tokens[i + 1] ~= "/usr/libexec/packet_capture_stop" then return false end i = i + 2 elseif token == "-F" then if tokens[i + 1] ~= filterfile then return false end i = i + 2 else return false end end return true end if arg[1] ~= nil then args = arg[1] if not validate_args(args) then error("Invalid tcpdump arguments") end if arg[2] ~= nil and arg[2] ~= "" then duration = arg[2] if not duration:match("^%d+$") then error("Invalid duration") end end end local filter = fs.stat(filterfile) if filter then args = args .. " -F " .. filterfile end local ubus_objects = { tcpdump = { } } conn:add( ubus_objects ) os.execute("sleep 1") local command = "tcpdump -l " .. args .. " 2>&1" if duration ~= "" then command = "timeout " .. duration .. " " .. command end local pipe = io.popen(command) for line in pipe:lines() do local params = { data = line } conn:notify(ubus_objects.tcpdump.__ubusobj, "tcpdump.data", params) end local pcap = fs.stat(pcapbase .. "0") if pcap then fs.move(pcapbase .. "0", outputfile) fs.remove(pcapbase .. "1") end if filter then fs.remove(filterfile) end conn:close() pipe:close() fs.remove("/var/run/packet_capture.pid")