mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-02 02:13:56 +08:00
🌴 Sync 2026-03-05 23:51:42
This commit is contained in:
1 parent
97c049ed0a
commit
0acff03804
14253 files changed
+3893239
No files matched your search
@@ -0,0 +1,356 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
|
||||
|
||||
Copyright 2013-2014 Diego Manas <diegomanas.dev@gmail.com>
|
||||
|
||||
Copyright (C) 2019, KFERMercer <iMercer@yeah.net>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
$Id$
|
||||
|
||||
2019-07-12 modified by KFERMercer <iMercer@yeah.com>:
|
||||
format code
|
||||
|
||||
]] --
|
||||
module("luci.controller.tcpdump", package.seeall)
|
||||
|
||||
tcpdump_root_folder = "/tmp/tcpdump/"
|
||||
tcpdump_cap_folder = tcpdump_root_folder .. "cap/"
|
||||
tcpdump_filter_folder = tcpdump_root_folder .. "filter/"
|
||||
pid_file = tcpdump_root_folder .. "tcpdump.pid"
|
||||
log_file = tcpdump_root_folder .. "tcpdump.log"
|
||||
out_file = tcpdump_root_folder .. "tcpdump.out"
|
||||
sleep_file = tcpdump_root_folder .. "tcpdump.sleep"
|
||||
|
||||
function index()
|
||||
template("myapp-mymodule/helloworld")
|
||||
entry({"admin", "network", "tcpdump"}, template("tcpdump"), _ "Tcpdump", 70).dependent =
|
||||
false
|
||||
|
||||
page = entry({"admin", "network", "tcpdump", "capture_start"},
|
||||
call("capture_start"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "tcpdump", "capture_stop"},
|
||||
call("capture_stop"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "tcpdump", "update"}, call("update"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "tcpdump", "capture_get"},
|
||||
call("capture_get"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "network", "tcpdump", "capture_remove"},
|
||||
call("capture_remove"), nil)
|
||||
page.leaf = true
|
||||
|
||||
end
|
||||
|
||||
function param_check(ifname, stop_value, stop_unit, filter)
|
||||
local check = false
|
||||
local message = {}
|
||||
-- Check interface
|
||||
-- Check for empty interface
|
||||
if ifname == nil or ifname == '' then
|
||||
table.insert(message, "Interface name is null or blank.")
|
||||
end
|
||||
-- Check for existing interface
|
||||
local nixio = require "nixio"
|
||||
for k, v in ipairs(nixio.getifaddrs()) do
|
||||
if v.family == "packet" then
|
||||
if ifname == v.name then
|
||||
check = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Check special interface name "any"
|
||||
if iface == 'any' then check = true end
|
||||
-- ERROR interface name not found
|
||||
if not check then
|
||||
table.insert(message, "Interface does not exist or is not valid.")
|
||||
end
|
||||
-- Check stop condition value
|
||||
if tonumber(stop_value) == nil then
|
||||
check = false
|
||||
table.insert(message, "Capture length parameter must be a number.")
|
||||
end
|
||||
-- Check stop condition flag
|
||||
if stop_unit == nil then
|
||||
check = false
|
||||
table.insert(message, "Capture unit is null or blank.")
|
||||
else
|
||||
stop_unit = string.upper(stop_unit)
|
||||
if stop_unit ~= "T" and stop_unit ~= "P" then
|
||||
check = false
|
||||
table.insert(message, "Capture unit must be Time(T) or packet(P).")
|
||||
end
|
||||
end
|
||||
return check, message
|
||||
end
|
||||
|
||||
function capture_start(ifname, stop_value, stop_unit, filter)
|
||||
local active, pid = capture_active()
|
||||
local res = {}
|
||||
local cmd = {}
|
||||
if active then
|
||||
cmd["ok"] = false
|
||||
cmd["msg"] = {"Previous capture is still ongoing!"}
|
||||
else
|
||||
local check, msg = param_check(ifname, stop_value, stop_unit, filter)
|
||||
if not check then
|
||||
cmd["ok"] = false
|
||||
cmd["msg"] = msg
|
||||
else
|
||||
-- Create temporal folders
|
||||
os.execute("mkdir -p " .. tcpdump_cap_folder)
|
||||
os.execute("mkdir -p " .. tcpdump_filter_folder)
|
||||
local prefix = "capture_" .. os.date("%Y-%m-%d_%H.%M.%S")
|
||||
local pcap_file = tcpdump_cap_folder .. prefix .. ".pcap"
|
||||
local filter_file = tcpdump_filter_folder .. prefix .. ".filter"
|
||||
string_to_file(filter_file, filter)
|
||||
string_to_file(out_file, prefix)
|
||||
tcpdump_start(ifname, stop_value, stop_unit, filter_file, pcap_file)
|
||||
res["filter"] = filter
|
||||
cmd["ok"] = true
|
||||
cmd["msg"] = {"Capture in progress.."}
|
||||
end
|
||||
end
|
||||
res["cmd"] = cmd
|
||||
res["capture"] = capture()
|
||||
res["list"] = list()
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(res)
|
||||
end
|
||||
|
||||
function string_to_file(file, data)
|
||||
if data == nil then data = "" end
|
||||
local f = io.open(file, "w")
|
||||
f:write(data)
|
||||
f:close()
|
||||
end
|
||||
|
||||
function tcpdump_start(ifname, stop_value, stop_unit, filter_file, pcap_file)
|
||||
local cmd = "tcpdump -i %s -F %s -w %s"
|
||||
cmd = string.format(cmd, ifname, filter_file, pcap_file)
|
||||
-- Packet limit if required
|
||||
if tonumber(stop_value) ~= 0 and stop_unit == "P" then
|
||||
cmd = cmd .. " -c " .. stop_value
|
||||
end
|
||||
-- Mute output and record PID on pid_file
|
||||
cmd = string.format("%s &> %s & echo $! > %s", cmd, log_file, pid_file)
|
||||
os.execute(cmd)
|
||||
-- Time limit if required
|
||||
if tonumber(stop_value) ~= 0 and stop_unit == "T" then
|
||||
local f = io.open(pid_file, "r")
|
||||
if f ~= nil then
|
||||
local pid = f:read()
|
||||
f:close()
|
||||
local t_out =
|
||||
string.format("sleep %s && kill %s &", stop_value, pid)
|
||||
os.execute(t_out)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function capture_stop()
|
||||
local res = {}
|
||||
local cmd = {}
|
||||
local _, active, pid = capture()
|
||||
if active then
|
||||
luci.sys.process.signal(pid, 9)
|
||||
cmd["ok"] = true
|
||||
cmd["msg"] = {"Capture has been terminated"}
|
||||
else
|
||||
cmd["ok"] = false
|
||||
cmd["msg"] = {"There was not active capture!"}
|
||||
end
|
||||
capture_cleanup()
|
||||
res["cmd"] = cmd
|
||||
res["capture"] = capture()
|
||||
res["list"] = list()
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(res)
|
||||
end
|
||||
|
||||
function capture_active()
|
||||
local f = io.open(pid_file, "r")
|
||||
if f ~= nil then
|
||||
pid = f:read()
|
||||
f:close()
|
||||
-- Check it is a legal PID and still alive
|
||||
if tonumber(pid) ~= nil and luci.sys.process.signal(pid, 0) then
|
||||
return true, pid
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function capture_log()
|
||||
local log
|
||||
local f = io.open(log_file, "r")
|
||||
if f ~= nil then
|
||||
log = f:read("*all")
|
||||
f:close()
|
||||
else
|
||||
log = ""
|
||||
end
|
||||
return log
|
||||
end
|
||||
|
||||
function capture_name()
|
||||
local cap_name = nil
|
||||
local f = io.open(out_file, "r")
|
||||
if f ~= nil then
|
||||
cap_name = f:read()
|
||||
f:close()
|
||||
end
|
||||
return cap_name
|
||||
end
|
||||
|
||||
function capture()
|
||||
local fs = require "nixio.fs"
|
||||
local res = {}
|
||||
local active, pid = capture_active()
|
||||
local msg
|
||||
res["active"] = active
|
||||
res["log"] = capture_log()
|
||||
if active then
|
||||
res["msg"] = "Capture in progress.."
|
||||
res["cap_name"] = capture_name()
|
||||
elseif fs.access(pid_file) then
|
||||
capture_cleanup()
|
||||
res["msg"] = "Process seems to be dead, removing pid file!"
|
||||
else
|
||||
res["msg"] = "No capture in progress"
|
||||
end
|
||||
return res, active, pid
|
||||
end
|
||||
|
||||
function capture_cleanup()
|
||||
-- Careless file removal
|
||||
os.remove(pid_file)
|
||||
os.remove(log_file)
|
||||
os.remove(out_file)
|
||||
local f = io.open(sleep_file, "r")
|
||||
if f ~= nil then
|
||||
pid = f:read()
|
||||
f:close()
|
||||
-- Kill sleep process if still alive
|
||||
if tonumber(pid) ~= nil or not luci.sys.process.signal(pid, 0) then
|
||||
luci.sys.process.signal(pid, 9)
|
||||
end
|
||||
end
|
||||
-- Careless file removal
|
||||
os.remove(sleep_file)
|
||||
end
|
||||
|
||||
function list_entries(cap_name)
|
||||
local fs = require "nixio.fs"
|
||||
local entries = {}
|
||||
local name
|
||||
local size
|
||||
local mtime
|
||||
local filter
|
||||
local glob_str
|
||||
if cap_name == nil then
|
||||
glob_str = tcpdump_cap_folder .. "*.pcap"
|
||||
else
|
||||
glob_str = tcpdump_cap_folder .. cap_name .. ".pcap"
|
||||
end
|
||||
for file in fs.glob(glob_str) do
|
||||
name = string.sub(fs.basename(file), 1, -6)
|
||||
size = fs.stat(file, "size")
|
||||
mtime = fs.stat(file, "ctime")
|
||||
-- Figure out if there's an associated filter
|
||||
if fs.access(tcpdump_filter_folder .. name .. ".filter") then
|
||||
filter = true
|
||||
else
|
||||
filter = false
|
||||
end
|
||||
table.insert(entries,
|
||||
{name = name, size = size, mtime = mtime, filter = filter})
|
||||
end
|
||||
return entries
|
||||
end
|
||||
|
||||
function list(cap_name)
|
||||
res = {}
|
||||
res["entries"] = list_entries(cap_name)
|
||||
res["update"] = (cap_name ~= nil)
|
||||
return res
|
||||
end
|
||||
|
||||
function update(cap_name)
|
||||
local res = {}
|
||||
local cmd = {}
|
||||
cmd["ok"] = true
|
||||
res["cmd"] = cmd
|
||||
res["capture"] = capture()
|
||||
res["list"] = list(cap_name)
|
||||
-- Build response
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(res)
|
||||
end
|
||||
|
||||
function pump_file(file, mime_str)
|
||||
local fh = io.open(file)
|
||||
local reader = luci.ltn12.source.file(fh)
|
||||
luci.http.header("Content-Disposition", "attachment; filename=\"" ..
|
||||
nixio.fs.basename(file) .. "\"")
|
||||
if mime_str ~= nil then
|
||||
luci.http.prepare_content(mime_str)
|
||||
else
|
||||
luci.http.prepare_content("application/octet-stream")
|
||||
end
|
||||
luci.ltn12.pump.all(reader, luci.http.write)
|
||||
fh:close()
|
||||
end
|
||||
|
||||
function capture_get(file_type, cap_name)
|
||||
if file_type == "all" then
|
||||
local system = require "luci.controller.admin.system"
|
||||
local tar_captures_cmd = "tar -c " .. tcpdump_cap_folder ..
|
||||
"*.pcap 2>/dev/null"
|
||||
local reader = system.ltn12_popen(tar_captures_cmd)
|
||||
luci.http.header('Content-Disposition',
|
||||
'attachment; filename="captures-%s.tar"' %
|
||||
{os.date("%Y-%m-%d_%H.%M.%S")})
|
||||
luci.http.prepare_content("application/x-tar")
|
||||
luci.ltn12.pump.all(reader, luci.http.write)
|
||||
elseif file_type == "pcap" then
|
||||
local file = tcpdump_cap_folder .. cap_name .. '.pcap'
|
||||
pump_file(file)
|
||||
elseif file_type == "filter" then
|
||||
local file = tcpdump_filter_folder .. cap_name .. '.filter'
|
||||
pump_file(file, "text/plain")
|
||||
else
|
||||
-- TODO
|
||||
end
|
||||
end
|
||||
|
||||
function capture_remove(cap_name)
|
||||
if cap_name == 'all' then
|
||||
local fs = require "nixio.fs"
|
||||
for file in fs.glob(tcpdump_cap_folder .. "*.pcap") do
|
||||
os.remove(file)
|
||||
end
|
||||
for file in fs.glob(tcpdump_filter_folder .. "*.filter") do
|
||||
os.remove(file)
|
||||
end
|
||||
else
|
||||
-- Remove both, capture and filter file
|
||||
os.remove(tcpdump_cap_folder .. cap_name .. ".pcap")
|
||||
os.remove(tcpdump_filter_folder .. cap_name .. ".filter")
|
||||
end
|
||||
-- Return current status and list
|
||||
update()
|
||||
end
|
||||
Reference in new issue
Block a user