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_NAME:=luci-app-passwall2
|
||||||
PKG_VERSION:=1.3
|
PKG_VERSION:=1.3
|
||||||
PKG_RELEASE:=10
|
PKG_RELEASE:=11
|
||||||
|
|
||||||
PKG_CONFIG_DEPENDS:= \
|
PKG_CONFIG_DEPENDS:= \
|
||||||
CONFIG_PACKAGE_$(PKG_NAME)_Transparent_Proxy \
|
CONFIG_PACKAGE_$(PKG_NAME)_Transparent_Proxy \
|
||||||
|
|
|
@ -302,7 +302,7 @@ run_v2ray() {
|
||||||
}
|
}
|
||||||
[ "$direct_dns_protocol" = "auto" ] && {
|
[ "$direct_dns_protocol" = "auto" ] && {
|
||||||
direct_dns_protocol="udp"
|
direct_dns_protocol="udp"
|
||||||
direct_dns_udp_server=${LOCAL_DNS}
|
direct_dns_udp_server=${AUTO_DNS}
|
||||||
}
|
}
|
||||||
case "$direct_dns_protocol" in
|
case "$direct_dns_protocol" in
|
||||||
udp)
|
udp)
|
||||||
|
@ -548,8 +548,7 @@ run_global() {
|
||||||
V2RAY_ARGS="${V2RAY_ARGS} direct_dns_protocol=${DIRECT_DNS_PROTOCOL}"
|
V2RAY_ARGS="${V2RAY_ARGS} direct_dns_protocol=${DIRECT_DNS_PROTOCOL}"
|
||||||
case "$DIRECT_DNS_PROTOCOL" in
|
case "$DIRECT_DNS_PROTOCOL" in
|
||||||
auto)
|
auto)
|
||||||
LOCAL_DNS=${DEFAULT_DNS:-119.29.29.29}
|
msg="${msg} 直连DNS:${AUTO_DNS}"
|
||||||
msg="${msg} 直连DNS:${LOCAL_DNS}"
|
|
||||||
;;
|
;;
|
||||||
udp)
|
udp)
|
||||||
LOCAL_DNS=${DIRECT_DNS}
|
LOCAL_DNS=${DIRECT_DNS}
|
||||||
|
@ -595,7 +594,7 @@ run_global() {
|
||||||
echolog ${msg}
|
echolog ${msg}
|
||||||
|
|
||||||
source $APP_PATH/helper_dnsmasq.sh stretch
|
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_CONFIG=$TMP_PATH/global.json
|
||||||
V2RAY_LOG=$TMP_PATH/global.log
|
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')
|
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 ' ' ',')
|
[ -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)
|
PROXY_IPV6=$(config_t_get global_forwarding ipv6_tproxy 0)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
|
@ -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).
|
|
@ -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
|
|
@ -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%>
|
|
@ -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 "目前没有可用的捕获."
|
|
@ -0,0 +1 @@
|
||||||
|
zh-cn
|
Loading…
Reference in New Issue