mirror of
https://github.com/kenzok8/small-package
synced 2025-01-07 07:06:58 +08:00
update 04-17 15:54:21
This commit is contained in:
parent
31a9f6b4d0
commit
e35b31a85f
@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall2
|
||||
PKG_VERSION:=1.3
|
||||
PKG_RELEASE:=10
|
||||
PKG_RELEASE:=11
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Transparent_Proxy \
|
||||
|
@ -302,7 +302,7 @@ run_v2ray() {
|
||||
}
|
||||
[ "$direct_dns_protocol" = "auto" ] && {
|
||||
direct_dns_protocol="udp"
|
||||
direct_dns_udp_server=${LOCAL_DNS}
|
||||
direct_dns_udp_server=${AUTO_DNS}
|
||||
}
|
||||
case "$direct_dns_protocol" in
|
||||
udp)
|
||||
@ -548,8 +548,7 @@ run_global() {
|
||||
V2RAY_ARGS="${V2RAY_ARGS} direct_dns_protocol=${DIRECT_DNS_PROTOCOL}"
|
||||
case "$DIRECT_DNS_PROTOCOL" in
|
||||
auto)
|
||||
LOCAL_DNS=${DEFAULT_DNS:-119.29.29.29}
|
||||
msg="${msg} 直连DNS:${LOCAL_DNS}"
|
||||
msg="${msg} 直连DNS:${AUTO_DNS}"
|
||||
;;
|
||||
udp)
|
||||
LOCAL_DNS=${DIRECT_DNS}
|
||||
@ -595,7 +594,7 @@ run_global() {
|
||||
echolog ${msg}
|
||||
|
||||
source $APP_PATH/helper_dnsmasq.sh stretch
|
||||
source $APP_PATH/helper_dnsmasq.sh add TMP_DNSMASQ_PATH=$TMP_DNSMASQ_PATH DNSMASQ_CONF_FILE=/tmp/dnsmasq.d/dnsmasq-passwall2.conf DEFAULT_DNS=$DEFAULT_DNS LOCAL_DNS=$LOCAL_DNS TUN_DNS=$TUN_DNS
|
||||
source $APP_PATH/helper_dnsmasq.sh add TMP_DNSMASQ_PATH=$TMP_DNSMASQ_PATH DNSMASQ_CONF_FILE=/tmp/dnsmasq.d/dnsmasq-passwall2.conf DEFAULT_DNS=$AUTO_DNS LOCAL_DNS=$LOCAL_DNS TUN_DNS=$TUN_DNS
|
||||
|
||||
V2RAY_CONFIG=$TMP_PATH/global.json
|
||||
V2RAY_LOG=$TMP_PATH/global.log
|
||||
@ -804,6 +803,7 @@ DNS_CACHE=$(config_t_get global dns_cache 1)
|
||||
|
||||
DEFAULT_DNS=$(uci show dhcp | grep "@dnsmasq" | grep "\.server=" | awk -F '=' '{print $2}' | sed "s/'//g" | tr ' ' '\n' | grep -v "\/" | head -2 | sed ':label;N;s/\n/,/;b label')
|
||||
[ -z "${DEFAULT_DNS}" ] && DEFAULT_DNS=$(echo -n $(sed -n 's/^nameserver[ \t]*\([^ ]*\)$/\1/p' "${RESOLVFILE}" | grep -v -E "0.0.0.0|127.0.0.1|::" | head -2) | tr ' ' ',')
|
||||
AUTO_DNS=${DEFAULT_DNS:-119.29.29.29}
|
||||
|
||||
PROXY_IPV6=$(config_t_get global_forwarding ipv6_tproxy 0)
|
||||
|
||||
|
202
luci-app-tcpdump/LICENSE
Normal file
202
luci-app-tcpdump/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
20
luci-app-tcpdump/Makefile
Normal file
20
luci-app-tcpdump/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
# Copyright (C) 2016 Openwrt.org
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
# Copyright (C) 2019, KFERMercer <iMercer@yeah.net>
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI support for tcpdump
|
||||
LUCI_DEPENDS:=+tcpdump
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_NAME:=luci-app-tcpdump
|
||||
PKG_VERSION:=1.0
|
||||
PKG_RELEASE:=2
|
||||
PKG_MAINTAINER:=<https://github.com/KFERMercer/luci-app-tcpdump>
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
13
luci-app-tcpdump/README.md
Normal file
13
luci-app-tcpdump/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# luci-app-tcpdump
|
||||
|
||||
LuCI interface for tcpdump.\
|
||||
It can be used to capture live TCP traffic for analysis.
|
||||
|
||||
## How to build into firmware:
|
||||
|
||||
`git clone https://github.com/KFERMercer/luci-app-tcpdump.git ./package/luci-app-tcpdump`
|
||||
|
||||
`make menuconfig`
|
||||
|
||||
|
||||
### Original codes built by [MacManas](https://github.com/MacManas/luci-app-tcpdump).
|
356
luci-app-tcpdump/luasrc/controller/tcpdump.lua
Normal file
356
luci-app-tcpdump/luasrc/controller/tcpdump.lua
Normal file
@ -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
|
246
luci-app-tcpdump/luasrc/view/tcpdump.htm
Normal file
246
luci-app-tcpdump/luasrc/view/tcpdump.htm
Normal file
@ -0,0 +1,246 @@
|
||||
<%#
|
||||
LuCI - Lua Configuration Interface
|
||||
|
||||
Copyright (C) 2013-2014, Diego Manas <diegomanas.dev@gmail.com>
|
||||
|
||||
Initial layout based on cshark project: https://github.com/cloudshark/cshark
|
||||
Copyright (C) 2014, QA Cafe, Inc.
|
||||
|
||||
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 & change tag name
|
||||
|
||||
-%>
|
||||
<%+header%>
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<legend><%:Start network capture%></legend>
|
||||
<div class="cbi-section-node">
|
||||
<table class="cbi-section-table">
|
||||
<tr>
|
||||
<th><%:Interface%></th>
|
||||
<th colspan='2'><%:seconds, packets%></th>
|
||||
<th><%:Filter%></th>
|
||||
<th><%:Actions%></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<select title="<%:Interface%>" style="width:auto" id="cap_ifname">
|
||||
<%
|
||||
local nixio = require "nixio"
|
||||
for k, v in ipairs(nixio.getifaddrs()) do
|
||||
if v.family == "packet" then
|
||||
%>
|
||||
<option value="<%=v.name%>"><%=v.name%> </option>
|
||||
<%
|
||||
end
|
||||
end
|
||||
%>
|
||||
<option value="any"><%:any%></option>
|
||||
</select>
|
||||
</td>
|
||||
<td colspan='2'>
|
||||
<input id="cap_stop_value" type="text" value="0" />
|
||||
<select title="<%:timeout, bytes, seconds%>" id="cap_stop_unit" style="width:auto">
|
||||
<option value="T"><%:seconds%></option>
|
||||
<option value="P"><%:packets%></option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input style="margin: 5px 0" type="text" title="<%:Filter%>" placeholder="filter" id="cap_filter" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" id="bt_capture" value="<%:Disabled%>" class="cbi-button" disabled />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<legend><%:Output%></legend>
|
||||
<span id="tcpdump-message"></span>
|
||||
<span id="tcpdump-log"></span>
|
||||
</fieldset>
|
||||
|
||||
<hr />
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<legend><%:Capture links%></legend>
|
||||
<div class="cbi-section-node">
|
||||
<table id="t_list" class="cbi-section-table">
|
||||
<tr class="cbi-section-table-titles">
|
||||
<th class="cbi-section-table-cell"><%:Capture file%></th>
|
||||
<th class="cbi-section-table-cell"><%:Modification date%></th>
|
||||
<th class="cbi-section-table-cell"><%:Capture size%></th>
|
||||
<th class="cbi-section-table-cell"><%:Actions%></th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<hr />
|
||||
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
|
||||
var capture_active = false;
|
||||
var capture_name;
|
||||
|
||||
function update_button() {
|
||||
var bt_capture = document.getElementById('bt_capture');
|
||||
if (!capture_active) {
|
||||
bt_capture.value = '<%:Start capture%>';
|
||||
bt_capture.onclick = capture_start;
|
||||
} else {
|
||||
bt_capture.value = '<%:Stop capture%>';
|
||||
bt_capture.onclick = capture_stop;
|
||||
}
|
||||
bt_capture.disabled = false;
|
||||
}
|
||||
|
||||
function capture_start() {
|
||||
var elem_ifname = document.getElementById('cap_ifname');
|
||||
var elem_stop_value = document.getElementById('cap_stop_value');
|
||||
var elem_stop_unit = document.getElementById('cap_stop_unit');
|
||||
var elem_filter = document.getElementById('cap_filter');
|
||||
|
||||
var ifname = elem_ifname.options[elem_ifname.selectedIndex].value;
|
||||
var stop_value = elem_stop_value.value;
|
||||
var stop_unit = elem_stop_unit.options[elem_stop_unit.selectedIndex].value;
|
||||
var filter = elem_filter.value;
|
||||
// TODO Implement checks?
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "tcpdump")%>/capture_start/' +
|
||||
ifname + '/' + stop_value + '/' + stop_unit + '/' + filter,
|
||||
null, update_callback)
|
||||
}
|
||||
|
||||
function capture_stop() {
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "tcpdump")%>/capture_stop',
|
||||
null, update_callback)
|
||||
}
|
||||
|
||||
function update_poll() {
|
||||
XHR.poll(10, '<%=luci.dispatcher.build_url("admin", "network", "tcpdump")%>/update',
|
||||
null, update_callback)
|
||||
}
|
||||
|
||||
function update_callback(xhr, json) {
|
||||
console.log(xhr)
|
||||
console.log(json)
|
||||
update_table(xhr, json)
|
||||
update_status(xhr, json)
|
||||
}
|
||||
|
||||
function update_table(xhr, json) {
|
||||
var table = document.getElementById("t_list");
|
||||
if (!table) return;
|
||||
// Remove all rows except headers
|
||||
while (table.rows.length > 1) {
|
||||
table.deleteRow(-1);
|
||||
}
|
||||
|
||||
if (!xhr) {
|
||||
var cell = table.insertRow(-1).insertCell(0);
|
||||
cell.colSpan = table.rows[0].cells.length;
|
||||
cell.innerHTML = '<em><br />Could not retrieve captures.</em>';
|
||||
return;
|
||||
}
|
||||
var entries = json.list.entries;
|
||||
if (!entries || !entries.length) {
|
||||
var cell = table.insertRow(-1).insertCell(0);
|
||||
cell.colSpan = table.rows[0].cells.length;
|
||||
cell.innerHTML = '<em><br />There are no captures available yet.</em>';
|
||||
return;
|
||||
}
|
||||
// Add rows
|
||||
var total_size = 0
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
var row = table.insertRow(-1);
|
||||
total_size += entries[i].size;
|
||||
var url = '<%=luci.dispatcher.build_url("admin", "network", "tcpdump")%>'
|
||||
row.insertCell().innerHTML = '<a href="#" onclick="capture_get(\'pcap\', \'' + entries[i].name + '\')">' + entries[i].name + '</a>';
|
||||
row.insertCell().innerHTML = human_date(entries[i].mtime);
|
||||
row.insertCell().innerHTML = human_size(entries[i].size);
|
||||
var cell = row.insertCell();
|
||||
cell.innerHTML += '<input type="button" onclick="capture_get(\'pcap\', \'' + entries[i].name + '\')" class="cbi-button cbi-button-download" value ="<%:pcap file%>" />';
|
||||
cell.innerHTML += '<input type="button" onclick="capture_get(\'filter\', \'' + entries[i].name + '\')" class="cbi-button cbi-button-download" value ="<%:filter file%>" />';
|
||||
cell.lastChild.disabled = !entries[i].filter;
|
||||
cell.innerHTML += '<input type="button" onclick="capture_remove(\'' + entries[i].name + '\')" class="cbi-button cbi-button-reset" value ="<%:Remove%>" />';
|
||||
}
|
||||
// Add summary row at the end
|
||||
var row = table.insertRow(-1);
|
||||
row.insertCell().innerHTML = '<b><%:All files%></b>';
|
||||
row.insertCell();
|
||||
row.insertCell().innerHTML = human_size(total_size);
|
||||
row.insertCell().innerHTML = '<input type="button" onclick="capture_get(\'all\')" class="cbi-button cbi-button-download" value ="<%:Download%>" />';
|
||||
row.cells[row.cells.length - 1].innerHTML += '<input type="button" onclick="capture_remove(\'all\')" class="cbi-button cbi-button-reset" value ="<%:Remove%>" />';
|
||||
}
|
||||
|
||||
function update_status(xhr, json) {
|
||||
capture_active = json.capture.active;
|
||||
capture_name = json.capture.cap_name;
|
||||
var in_use;
|
||||
in_use = document.getElementById("tcpdump-message");
|
||||
var msg = ""
|
||||
if (json.cmd.hasOwnProperty("msg")) {
|
||||
for (var i = 0; i < json.cmd.msg.length; i++) {
|
||||
msg += json.cmd.msg[i] + "\n";
|
||||
}
|
||||
} else {
|
||||
msg = json.capture.msg;
|
||||
}
|
||||
in_use.innerHTML = "<pre>" + msg + "</pre>";
|
||||
in_use = document.getElementById("tcpdump-log");
|
||||
if (capture_active) {
|
||||
in_use.innerHTML = "<pre>" + json.capture.log + "</pre>";
|
||||
} else {
|
||||
in_use.innerHTML = ""
|
||||
}
|
||||
update_button()
|
||||
}
|
||||
|
||||
function human_size(size) {
|
||||
var units = ["B", "KiB", "MiB", "GiB"]
|
||||
var unit_index = 0
|
||||
while (size > 1024 && unit_index < 3) {
|
||||
unit_index += 1
|
||||
size /= 1024
|
||||
}
|
||||
return Math.round(size * 100) / 100 + " " + units[unit_index]
|
||||
}
|
||||
|
||||
function human_date(date_seconds) {
|
||||
var date = new Date(date_seconds * 1000)
|
||||
return date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear() + " " +
|
||||
date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds()
|
||||
}
|
||||
|
||||
function capture_get(type, cap_name) {
|
||||
var iframe;
|
||||
iframe = document.getElementById("hiddenDownloader");
|
||||
if (iframe == null) {
|
||||
iframe = document.createElement('iframe');
|
||||
iframe.id = "hiddenDownloader";
|
||||
iframe.style.visibility = 'hidden';
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
iframe.src = '<%=luci.dispatcher.build_url("admin", "network", "tcpdump")%>/capture_get/' + type + '/' + cap_name;
|
||||
}
|
||||
|
||||
function capture_remove(cap_name) {
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "tcpdump")%>/capture_remove/' + cap_name, null, update_callback)
|
||||
}
|
||||
|
||||
document.onload = update_poll();
|
||||
//]]></script>
|
||||
<%+footer%>
|
107
luci-app-tcpdump/po/zh-cn/tcpdump.po
Normal file
107
luci-app-tcpdump/po/zh-cn/tcpdump.po
Normal file
@ -0,0 +1,107 @@
|
||||
msgid "Tcpdump"
|
||||
msgstr "Tcpdump 流量监控"
|
||||
|
||||
msgid "Start network capture"
|
||||
msgstr "Tcpdump 流量监控"
|
||||
|
||||
msgid "Interface"
|
||||
msgstr "捕获指定的接口"
|
||||
|
||||
msgid "seconds, packets"
|
||||
msgstr "捕获限制"
|
||||
|
||||
msgid "Filter"
|
||||
msgstr "过滤"
|
||||
|
||||
msgid "Actions"
|
||||
msgstr "操作"
|
||||
|
||||
msgid "any"
|
||||
msgstr "所有"
|
||||
|
||||
msgid "timeout, bytes, seconds"
|
||||
msgstr "超时, 字节, 秒"
|
||||
|
||||
msgid "seconds"
|
||||
msgstr "秒"
|
||||
|
||||
msgid "packets"
|
||||
msgstr "数据包"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "已禁用"
|
||||
|
||||
msgid "Output"
|
||||
msgstr "输出"
|
||||
|
||||
msgid "Capture links"
|
||||
msgstr "捕获结果"
|
||||
|
||||
msgid "Capture file"
|
||||
msgstr "文件名"
|
||||
|
||||
msgid "Modification date"
|
||||
msgstr "停止时间"
|
||||
|
||||
msgid "Capture size"
|
||||
msgstr "文件大小"
|
||||
|
||||
msgid "Start capture"
|
||||
msgstr "开始捕获"
|
||||
|
||||
msgid "Stop capture"
|
||||
msgstr "停止捕获"
|
||||
|
||||
msgid "pcap file"
|
||||
msgstr ".pcap文件"
|
||||
|
||||
msgid "filter file"
|
||||
msgstr ".filter文件"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "删除"
|
||||
|
||||
msgid "All files"
|
||||
msgstr "所有文件"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "下载"
|
||||
|
||||
msgid "Interface name is null or blank."
|
||||
msgstr "请指定要捕获的接口."
|
||||
|
||||
msgid "Interface does not exist or is not valid."
|
||||
msgstr "接口不存在或无效."
|
||||
|
||||
msgid "Capture length parameter must be a number."
|
||||
msgstr "捕获长度参数必须是数字."
|
||||
|
||||
msgid "Capture unit is null or blank."
|
||||
msgstr "捕获单位为空或空白."
|
||||
|
||||
msgid "Capture unit must be Time(T) or packet(P)."
|
||||
msgstr "捕获单位必须是时间(T)或包(P)."
|
||||
|
||||
msgid "Previous capture is still ongoing!"
|
||||
msgstr "先前的捕获未停止!"
|
||||
|
||||
msgid "Capture in progress.."
|
||||
msgstr "正在捕获..."
|
||||
|
||||
msgid "Capture has been terminated"
|
||||
msgstr "捕获已被终止"
|
||||
|
||||
msgid "There was not active capture!"
|
||||
msgstr "捕获活动未运行!"
|
||||
|
||||
msgid "Process seems to be dead, removing pid file!"
|
||||
msgstr "进程失去响应, 正在删除pid文件!"
|
||||
|
||||
msgid "No capture in progress"
|
||||
msgstr "没有正在进行的捕获"
|
||||
|
||||
msgid "Could not retrieve captures."
|
||||
msgstr "无法检索捕获."
|
||||
|
||||
msgid "There are no captures available yet."
|
||||
msgstr "目前没有可用的捕获."
|
1
luci-app-tcpdump/po/zh_Hans
Symbolic link
1
luci-app-tcpdump/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
Loading…
Reference in New Issue
Block a user