mirror of
https://github.com/SunBK201/UA3F.git
synced 2025-12-16 08:44:29 +00:00
refactor: refactor luci cbi
This commit is contained in:
parent
e1e02929f8
commit
30fb3ad278
@ -11,7 +11,13 @@ local ua3f = cbi.Map("ua3f",
|
||||
Across the Campus we can reach every corner in the world.
|
||||
]]
|
||||
)
|
||||
local fields = require("luci.model.cbi.ua3f.fields")
|
||||
local status = require("luci.model.cbi.ua3f.status")
|
||||
local general = require("luci.model.cbi.ua3f.general")
|
||||
local rule = require("luci.model.cbi.ua3f.rule")
|
||||
local desync = require("luci.model.cbi.ua3f.desync")
|
||||
local others = require("luci.model.cbi.ua3f.others")
|
||||
local statistics = require("luci.model.cbi.ua3f.statistics")
|
||||
local log = require("luci.model.cbi.ua3f.log")
|
||||
|
||||
function create_sections(map)
|
||||
local sections = {}
|
||||
@ -22,10 +28,10 @@ function create_sections(map)
|
||||
-- General Section with tabs
|
||||
sections.general = map:section(NamedSection, "main", "ua3f", translate("General"))
|
||||
sections.general:tab("general", translate("Settings"))
|
||||
sections.general:tab("rewrite", translate("Rewrite Rules"))
|
||||
sections.general:tab("rules", translate("Rewrite Rules"))
|
||||
sections.general:tab("desync", translate("Desync Settings"))
|
||||
sections.general:tab("others", translate("Others Settings"))
|
||||
sections.general:tab("stats", translate("Statistics"))
|
||||
sections.general:tab("statistics", translate("Statistics"))
|
||||
sections.general:tab("log", translate("Log"))
|
||||
|
||||
return sections
|
||||
@ -33,12 +39,12 @@ end
|
||||
|
||||
local sections = create_sections(ua3f)
|
||||
|
||||
fields.add_status_fields(sections.status)
|
||||
fields.add_general_fields(sections.general)
|
||||
fields.add_rewrite_fields(sections.general)
|
||||
fields.add_desync_fields(sections.general)
|
||||
fields.add_others_fields(sections.general)
|
||||
fields.add_stats_fields(sections.general)
|
||||
fields.add_log_fields(sections.general)
|
||||
status.add_status_fields(sections.status)
|
||||
general.add_general_fields(sections.general)
|
||||
rule.add_rule_fields(sections.general)
|
||||
desync.add_desync_fields(sections.general)
|
||||
others.add_others_fields(sections.general)
|
||||
statistics.add_statistics_fields(sections.general)
|
||||
log.add_log_fields(sections.general)
|
||||
|
||||
return ua3f
|
||||
|
||||
42
openwrt/files/luci/model/cbi/ua3f/desync.lua
Normal file
42
openwrt/files/luci/model/cbi/ua3f/desync.lua
Normal file
@ -0,0 +1,42 @@
|
||||
local M = {}
|
||||
|
||||
local cbi = require("luci.cbi")
|
||||
local i18n = require("luci.i18n")
|
||||
local utils = require("luci.model.cbi.ua3f.utils")
|
||||
local translate = i18n.translate
|
||||
|
||||
local Flag = cbi.Flag
|
||||
local Value = cbi.Value
|
||||
local DummyValue = cbi.DummyValue
|
||||
|
||||
function M.add_desync_fields(section)
|
||||
-- Enable TCP Desync
|
||||
local desync_enabled = section:taboption("desync", Flag, "desync_enabled", translate("Enable TCP Desync"))
|
||||
desync_enabled.description = translate("Enable TCP Desynchronization to evade DPI")
|
||||
|
||||
if not utils.nfqueue_exists() then
|
||||
local nfqueue_warning = section:taboption("desync", DummyValue, "_desync_nfqueue_warning", " ")
|
||||
nfqueue_warning.rawhtml = true
|
||||
nfqueue_warning:depends("desync_enabled", 1)
|
||||
function nfqueue_warning.cfgvalue(self, section)
|
||||
return "<strong style='color:red;'>" ..
|
||||
translate("Recommend install kmod-nft-queue package for NFQUEUE mode") .. "</strong>"
|
||||
end
|
||||
end
|
||||
|
||||
-- CT Byte Setting
|
||||
local ct_byte = section:taboption("desync", Value, "desync_ct_bytes", translate("Desync Bytes"))
|
||||
ct_byte.placeholder = "1500"
|
||||
ct_byte.datatype = "uinteger"
|
||||
ct_byte.description = translate("Number of bytes for fragmented random emission")
|
||||
ct_byte:depends("desync_enabled", "1")
|
||||
|
||||
-- CT Packets Setting
|
||||
local ct_packets = section:taboption("desync", Value, "desync_ct_packets", translate("Desync Packets"))
|
||||
ct_packets.placeholder = "8"
|
||||
ct_packets.datatype = "uinteger"
|
||||
ct_packets.description = translate("Number of packets for fragmented random emission")
|
||||
ct_packets:depends("desync_enabled", "1")
|
||||
end
|
||||
|
||||
return M
|
||||
@ -1,303 +0,0 @@
|
||||
local M = {}
|
||||
|
||||
local cbi = require("luci.cbi")
|
||||
local i18n = require("luci.i18n")
|
||||
local sys = require("luci.sys")
|
||||
local translate = i18n.translate
|
||||
|
||||
local Flag = cbi.Flag
|
||||
local Value = cbi.Value
|
||||
local ListValue = cbi.ListValue
|
||||
local DummyValue = cbi.DummyValue
|
||||
local TextValue = cbi.TextValue
|
||||
|
||||
function cmd_exists(cmd)
|
||||
return sys.call("command -v " .. cmd .. " >/dev/null 2>&1") == 0
|
||||
end
|
||||
|
||||
function nfqueue_exists()
|
||||
local opkg = cmd_exists("opkg") and sys.call("opkg list-installed kmod-nft-queue | grep -q kmod-nft-queue") == 0
|
||||
local apk = cmd_exists("apk") and (sys.call("apk info | grep -q kmod-nft-queue") == 0)
|
||||
return opkg or apk
|
||||
end
|
||||
|
||||
function tproxy_exists()
|
||||
local opkg = cmd_exists("opkg") and sys.call("opkg list-installed kmod-nft-tproxy | grep -q kmod-nft-tproxy") == 0
|
||||
local apk = cmd_exists("apk") and (sys.call("apk info | grep -q kmod-nft-tproxy") == 0)
|
||||
return opkg or apk
|
||||
end
|
||||
|
||||
-- Status Section Fields
|
||||
function M.add_status_fields(section)
|
||||
-- Enabled Flag
|
||||
section:option(Flag, "enabled", translate("Enabled"))
|
||||
|
||||
-- Running Status Display
|
||||
local running = section:option(DummyValue, "running", translate("Status"))
|
||||
running.rawhtml = true
|
||||
running.cfgvalue = function(self, section)
|
||||
local pid = sys.exec("pidof ua3f")
|
||||
if pid == "" then
|
||||
return "<input disabled type='button' style='opacity: 1;' class='btn cbi-button cbi-button-reset' value='" ..
|
||||
translate("Stop") .. "'/>"
|
||||
else
|
||||
return "<input disabled type='button' style='opacity: 1;' class='btn cbi-button cbi-button-add' value='" ..
|
||||
translate("Running") .. "'/>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- General Tab Fields
|
||||
function M.add_general_fields(section)
|
||||
-- Server Mode
|
||||
local server_mode = section:taboption("general", ListValue, "server_mode", translate("Server Mode"))
|
||||
server_mode:value("HTTP", "HTTP")
|
||||
server_mode:value("SOCKS5", "SOCKS5")
|
||||
server_mode:value("TPROXY", "TPROXY")
|
||||
server_mode:value("REDIRECT", "REDIRECT")
|
||||
server_mode:value("NFQUEUE", "NFQUEUE")
|
||||
server_mode.default = "TPROXY"
|
||||
|
||||
if not tproxy_exists() then
|
||||
local tproxy_warning = section:taboption("general", DummyValue, "_tproxy_warning", " ")
|
||||
tproxy_warning.rawhtml = true
|
||||
tproxy_warning:depends("server_mode", "TPROXY")
|
||||
function tproxy_warning.cfgvalue(self, section)
|
||||
return "<strong style='color:red;'>" ..
|
||||
translate("Recommend install kmod-nft-tproxy package for TPROXY mode") .. "</strong>"
|
||||
end
|
||||
end
|
||||
|
||||
if not nfqueue_exists() then
|
||||
local nfqueue_warning = section:taboption("general", DummyValue, "_nfqueue_warning", " ")
|
||||
nfqueue_warning.rawhtml = true
|
||||
nfqueue_warning:depends("server_mode", "NFQUEUE")
|
||||
function nfqueue_warning.cfgvalue(self, section)
|
||||
return "<strong style='color:red;'>" ..
|
||||
translate("Recommend install kmod-nft-queue package for NFQUEUE mode") .. "</strong>"
|
||||
end
|
||||
end
|
||||
|
||||
-- Bind Address
|
||||
local bind = section:taboption("general", Value, "bind", translate("Bind Address"))
|
||||
bind:value("127.0.0.1")
|
||||
bind:value("0.0.0.0")
|
||||
bind:depends("server_mode", "HTTP")
|
||||
bind:depends("server_mode", "SOCKS5")
|
||||
|
||||
-- Port
|
||||
local port = section:taboption("general", Value, "port", translate("Port"))
|
||||
port.placeholder = "1080"
|
||||
port:depends("server_mode", "HTTP")
|
||||
port:depends("server_mode", "SOCKS5")
|
||||
port:depends("server_mode", "TPROXY")
|
||||
port:depends("server_mode", "REDIRECT")
|
||||
|
||||
-- Rewrite Mode
|
||||
local rewrite_mode = section:taboption("general", ListValue, "rewrite_mode", translate("Rewrite Mode"))
|
||||
rewrite_mode:value("DIRECT", translate("Direct Forward"))
|
||||
rewrite_mode:value("GLOBAL", translate("Global Rewrite"))
|
||||
rewrite_mode:value("RULES", translate("Rule Based"))
|
||||
rewrite_mode.default = "GLOBAL"
|
||||
rewrite_mode.description = translate(
|
||||
"Direct Forward: No rewriting. Global Rewrite: Rewrite all User-Agents. Rule Based: Use rewrite rules to determine behavior.")
|
||||
|
||||
-- User-Agent (for Global Rewrite)
|
||||
local ua = section:taboption("general", Value, "ua", translate("User-Agent"))
|
||||
ua.placeholder = "FFF"
|
||||
ua.description = translate("User-Agent after rewrite")
|
||||
ua:depends("rewrite_mode", "GLOBAL")
|
||||
ua:depends("server_mode", "NFQUEUE")
|
||||
|
||||
-- User-Agent Regex
|
||||
local regex = section:taboption("general", Value, "ua_regex", translate("User-Agent Regex"))
|
||||
regex.description = translate("Regular expression pattern for matching User-Agent")
|
||||
regex:depends("rewrite_mode", "GLOBAL")
|
||||
regex:depends("server_mode", "NFQUEUE")
|
||||
|
||||
-- Partial Replace
|
||||
local partialReplace = section:taboption("general", Flag, "partial_replace", translate("Partial Replace"))
|
||||
partialReplace.description =
|
||||
translate(
|
||||
"Replace only the matched part of the User-Agent, only works when User-Agent Regex is not empty")
|
||||
partialReplace.default = "0"
|
||||
partialReplace:depends("rewrite_mode", "GLOBAL")
|
||||
partialReplace:depends("server_mode", "NFQUEUE")
|
||||
end
|
||||
|
||||
-- Rewrite Rules Tab Fields
|
||||
function M.add_rewrite_fields(section)
|
||||
local rules = section:taboption("rewrite", DummyValue, "")
|
||||
rules.template = "ua3f/rules"
|
||||
end
|
||||
|
||||
-- Statistics Tab Fields
|
||||
function M.add_stats_fields(section)
|
||||
local stats = section:taboption("stats", DummyValue, "")
|
||||
stats.template = "ua3f/statistics"
|
||||
end
|
||||
|
||||
-- Log Tab Fields
|
||||
function M.add_log_fields(section)
|
||||
-- Log Display
|
||||
local log = section:taboption("log", TextValue, "log")
|
||||
log.readonly = true
|
||||
log.rows = 30
|
||||
log.wrap = "off"
|
||||
function log.cfgvalue(self, section)
|
||||
local logfile = "/var/log/ua3f/ua3f.log"
|
||||
local fs = require("nixio.fs")
|
||||
if not fs.access(logfile) then
|
||||
return ""
|
||||
end
|
||||
local n = tonumber(luci.model.uci.cursor():get("ua3f", section, "log_lines")) or 1000
|
||||
return luci.sys.exec("tail -n " .. n .. " " .. logfile)
|
||||
end
|
||||
|
||||
function log.write(self, section, value) end
|
||||
|
||||
function log.render(self, section, scope)
|
||||
TextValue.render(self, section, scope)
|
||||
luci.http.write("<script>")
|
||||
luci.http.write([[
|
||||
var textarea = document.getElementById('cbid.ua3f.main.log');
|
||||
if (textarea) {
|
||||
textarea.removeAttribute('name');
|
||||
textarea.scrollTop = textarea.scrollHeight;
|
||||
}
|
||||
]])
|
||||
luci.http.write("</script>")
|
||||
end
|
||||
|
||||
-- Log Level
|
||||
local log_level = section:taboption("log", ListValue, "log_level", translate("Log Level"))
|
||||
log_level:value("DEBUG")
|
||||
log_level:value("INFO")
|
||||
log_level:value("WARN")
|
||||
log_level:value("ERROR")
|
||||
log_level.default = "WARN"
|
||||
log_level.description = translate(
|
||||
"Sets the logging level. Do not keep the log level set to DEBUG for an extended period of time.")
|
||||
|
||||
-- Log Lines
|
||||
local logLines = section:taboption("log", Value, "log_lines", translate("Display Lines"))
|
||||
logLines.default = "1000"
|
||||
logLines.datatype = "uinteger"
|
||||
logLines.rmempty = false
|
||||
|
||||
-- Button Container (DummyValue to hold all buttons)
|
||||
local button_container = section:taboption("log", DummyValue, "_button_container", translate("Log Actions"))
|
||||
button_container.rawhtml = true
|
||||
|
||||
function button_container.cfgvalue(self, section)
|
||||
return ""
|
||||
end
|
||||
|
||||
function button_container.render(self, section, scope)
|
||||
luci.http.write([[
|
||||
<div class="cbi-value" id="cbi-ua3f-main-_button_container">
|
||||
<label class="cbi-value-title">]] .. translate("Log Management") .. [[</label>
|
||||
<div class="cbi-value-field" style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<input type="button" class="btn cbi-button cbi-button-reset"
|
||||
value="]] .. translate("Clear Logs") .. [[" id="ua3f-clearlog-btn"/>
|
||||
<input type="button" class="btn cbi-button cbi-button-apply"
|
||||
value="]] .. translate("Download Logs") .. [[" id="ua3f-download-btn"/>
|
||||
<input type="button" class="btn cbi-button cbi-button-save"
|
||||
value="]] .. translate("Issue Report") .. [[" id="ua3f-issue-btn"/>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
// Clear Log Button
|
||||
document.getElementById('ua3f-clearlog-btn').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
fetch(']] .. luci.dispatcher.build_url("admin/services/ua3f/clear_log") .. [[', {method: 'POST'})
|
||||
.then(resp => {
|
||||
if (resp.ok) {
|
||||
var textarea = document.getElementById('cbid.ua3f.main.log');
|
||||
if (textarea) textarea.value = "";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Download Log Button
|
||||
document.getElementById('ua3f-download-btn').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
window.location.href = ']] .. luci.dispatcher.build_url("admin/services/ua3f/download_log") .. [[';
|
||||
});
|
||||
|
||||
// Issue Report Button
|
||||
document.getElementById('ua3f-issue-btn').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
window.open('https://github.com/SunBK201/UA3F/issues/new?template=bug-report.md', '_blank');
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
]])
|
||||
end
|
||||
|
||||
return log
|
||||
end
|
||||
|
||||
function M.add_desync_fields(section)
|
||||
-- Enable TCP Desync
|
||||
local desync_enabled = section:taboption("desync", Flag, "desync_enabled", translate("Enable TCP Desync"))
|
||||
desync_enabled.description = translate("Enable TCP Desynchronization to evade DPI")
|
||||
|
||||
if not nfqueue_exists() then
|
||||
local nfqueue_warning = section:taboption("desync", DummyValue, "_desync_nfqueue_warning", " ")
|
||||
nfqueue_warning.rawhtml = true
|
||||
nfqueue_warning:depends("desync_enabled", 1)
|
||||
function nfqueue_warning.cfgvalue(self, section)
|
||||
return "<strong style='color:red;'>" ..
|
||||
translate("Recommend install kmod-nft-queue package for NFQUEUE mode") .. "</strong>"
|
||||
end
|
||||
end
|
||||
|
||||
-- CT Byte Setting
|
||||
local ct_byte = section:taboption("desync", Value, "desync_ct_bytes", translate("Desync Bytes"))
|
||||
ct_byte.placeholder = "1500"
|
||||
ct_byte.datatype = "uinteger"
|
||||
ct_byte.description = translate("Number of bytes for fragmented random emission")
|
||||
ct_byte:depends("desync_enabled", "1")
|
||||
|
||||
-- CT Packets Setting
|
||||
local ct_packets = section:taboption("desync", Value, "desync_ct_packets", translate("Desync Packets"))
|
||||
ct_packets.placeholder = "8"
|
||||
ct_packets.datatype = "uinteger"
|
||||
ct_packets.description = translate("Number of packets for fragmented random emission")
|
||||
ct_packets:depends("desync_enabled", "1")
|
||||
end
|
||||
|
||||
-- Others Tab Fields
|
||||
function M.add_others_fields(section)
|
||||
-- TTL Setting
|
||||
local ttl = section:taboption("others", Flag, "set_ttl", translate("Set TTL"))
|
||||
ttl.description = translate("Set the TTL 64 for packets")
|
||||
|
||||
-- TCP Timestamp Deletion
|
||||
local tcpts = section:taboption("others", Flag, "del_tcpts", translate("Delete TCP Timestamps"))
|
||||
tcpts.description = translate("Remove TCP Timestamp option")
|
||||
|
||||
-- TCP Initial Window
|
||||
local tcp_init_window = section:taboption("others", Flag, "set_tcp_init_window", translate("Set TCP Initial Window"))
|
||||
tcp_init_window.description = translate("Set the TCP Initial Window to 65535 for SYN packets")
|
||||
|
||||
-- IP ID Setting
|
||||
local ipid = section:taboption("others", Flag, "set_ipid", translate("Set IP ID"))
|
||||
ipid.description = translate("Set the IP ID to 0 for packets")
|
||||
|
||||
if not nfqueue_exists() then
|
||||
local nfqueue_warning = section:taboption("others", DummyValue, "_others_nfqueue_warning", " ")
|
||||
nfqueue_warning.rawhtml = true
|
||||
nfqueue_warning:depends("del_tcpts", 1)
|
||||
nfqueue_warning:depends("set_tcp_init_window", 1)
|
||||
nfqueue_warning:depends("set_ipid", 1)
|
||||
function nfqueue_warning.cfgvalue(self, section)
|
||||
return "<strong style='color:red;'>" ..
|
||||
translate("Recommend install kmod-nft-queue package for NFQUEUE mode") .. "</strong>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
90
openwrt/files/luci/model/cbi/ua3f/general.lua
Normal file
90
openwrt/files/luci/model/cbi/ua3f/general.lua
Normal file
@ -0,0 +1,90 @@
|
||||
local M = {}
|
||||
|
||||
local cbi = require("luci.cbi")
|
||||
local i18n = require("luci.i18n")
|
||||
local utils = require("luci.model.cbi.ua3f.utils")
|
||||
local translate = i18n.translate
|
||||
|
||||
local Flag = cbi.Flag
|
||||
local Value = cbi.Value
|
||||
local ListValue = cbi.ListValue
|
||||
local DummyValue = cbi.DummyValue
|
||||
|
||||
function M.add_general_fields(section)
|
||||
-- Server Mode
|
||||
local server_mode = section:taboption("general", ListValue, "server_mode", translate("Server Mode"))
|
||||
server_mode:value("HTTP", "HTTP")
|
||||
server_mode:value("SOCKS5", "SOCKS5")
|
||||
server_mode:value("TPROXY", "TPROXY")
|
||||
server_mode:value("REDIRECT", "REDIRECT")
|
||||
server_mode:value("NFQUEUE", "NFQUEUE")
|
||||
server_mode.default = "TPROXY"
|
||||
|
||||
if not utils.tproxy_exists() then
|
||||
local tproxy_warning = section:taboption("general", DummyValue, "_tproxy_warning", " ")
|
||||
tproxy_warning.rawhtml = true
|
||||
tproxy_warning:depends("server_mode", "TPROXY")
|
||||
function tproxy_warning.cfgvalue(self, section)
|
||||
return "<strong style='color:red;'>" ..
|
||||
translate("Recommend install kmod-nft-tproxy package for TPROXY mode") .. "</strong>"
|
||||
end
|
||||
end
|
||||
|
||||
if not utils.nfqueue_exists() then
|
||||
local nfqueue_warning = section:taboption("general", DummyValue, "_nfqueue_warning", " ")
|
||||
nfqueue_warning.rawhtml = true
|
||||
nfqueue_warning:depends("server_mode", "NFQUEUE")
|
||||
function nfqueue_warning.cfgvalue(self, section)
|
||||
return "<strong style='color:red;'>" ..
|
||||
translate("Recommend install kmod-nft-queue package for NFQUEUE mode") .. "</strong>"
|
||||
end
|
||||
end
|
||||
|
||||
-- Bind Address
|
||||
local bind = section:taboption("general", Value, "bind", translate("Bind Address"))
|
||||
bind:value("127.0.0.1")
|
||||
bind:value("0.0.0.0")
|
||||
bind:depends("server_mode", "HTTP")
|
||||
bind:depends("server_mode", "SOCKS5")
|
||||
|
||||
-- Port
|
||||
local port = section:taboption("general", Value, "port", translate("Port"))
|
||||
port.placeholder = "1080"
|
||||
port:depends("server_mode", "HTTP")
|
||||
port:depends("server_mode", "SOCKS5")
|
||||
port:depends("server_mode", "TPROXY")
|
||||
port:depends("server_mode", "REDIRECT")
|
||||
|
||||
-- Rewrite Mode
|
||||
local rewrite_mode = section:taboption("general", ListValue, "rewrite_mode", translate("Rewrite Mode"))
|
||||
rewrite_mode:value("DIRECT", translate("Direct Forward"))
|
||||
rewrite_mode:value("GLOBAL", translate("Global Rewrite"))
|
||||
rewrite_mode:value("RULES", translate("Rule Based"))
|
||||
rewrite_mode.default = "GLOBAL"
|
||||
rewrite_mode.description = translate(
|
||||
"Direct Forward: No rewriting. Global Rewrite: Rewrite all User-Agents. Rule Based: Use rewrite rules to determine behavior.")
|
||||
|
||||
-- User-Agent (for Global Rewrite)
|
||||
local ua = section:taboption("general", Value, "ua", translate("User-Agent"))
|
||||
ua.placeholder = "FFF"
|
||||
ua.description = translate("User-Agent after rewrite")
|
||||
ua:depends("rewrite_mode", "GLOBAL")
|
||||
ua:depends("server_mode", "NFQUEUE")
|
||||
|
||||
-- User-Agent Regex
|
||||
local regex = section:taboption("general", Value, "ua_regex", translate("User-Agent Regex"))
|
||||
regex.description = translate("Regular expression pattern for matching User-Agent")
|
||||
regex:depends("rewrite_mode", "GLOBAL")
|
||||
regex:depends("server_mode", "NFQUEUE")
|
||||
|
||||
-- Partial Replace
|
||||
local partialReplace = section:taboption("general", Flag, "partial_replace", translate("Partial Replace"))
|
||||
partialReplace.description =
|
||||
translate(
|
||||
"Replace only the matched part of the User-Agent, only works when User-Agent Regex is not empty")
|
||||
partialReplace.default = "0"
|
||||
partialReplace:depends("rewrite_mode", "GLOBAL")
|
||||
partialReplace:depends("server_mode", "NFQUEUE")
|
||||
end
|
||||
|
||||
return M
|
||||
113
openwrt/files/luci/model/cbi/ua3f/log.lua
Normal file
113
openwrt/files/luci/model/cbi/ua3f/log.lua
Normal file
@ -0,0 +1,113 @@
|
||||
local M = {}
|
||||
|
||||
local cbi = require("luci.cbi")
|
||||
local i18n = require("luci.i18n")
|
||||
local translate = i18n.translate
|
||||
|
||||
local Value = cbi.Value
|
||||
local ListValue = cbi.ListValue
|
||||
local DummyValue = cbi.DummyValue
|
||||
local TextValue = cbi.TextValue
|
||||
|
||||
function M.add_log_fields(section)
|
||||
-- Log Display
|
||||
local log = section:taboption("log", TextValue, "log")
|
||||
log.readonly = true
|
||||
log.rows = 30
|
||||
log.wrap = "off"
|
||||
function log.cfgvalue(self, section)
|
||||
local logfile = "/var/log/ua3f/ua3f.log"
|
||||
local fs = require("nixio.fs")
|
||||
if not fs.access(logfile) then
|
||||
return ""
|
||||
end
|
||||
local n = tonumber(luci.model.uci.cursor():get("ua3f", section, "log_lines")) or 1000
|
||||
return luci.sys.exec("tail -n " .. n .. " " .. logfile)
|
||||
end
|
||||
|
||||
function log.write(self, section, value) end
|
||||
|
||||
function log.render(self, section, scope)
|
||||
TextValue.render(self, section, scope)
|
||||
luci.http.write("<script>")
|
||||
luci.http.write([[
|
||||
var textarea = document.getElementById('cbid.ua3f.main.log');
|
||||
if (textarea) {
|
||||
textarea.removeAttribute('name');
|
||||
textarea.scrollTop = textarea.scrollHeight;
|
||||
}
|
||||
]])
|
||||
luci.http.write("</script>")
|
||||
end
|
||||
|
||||
-- Log Level
|
||||
local log_level = section:taboption("log", ListValue, "log_level", translate("Log Level"))
|
||||
log_level:value("DEBUG")
|
||||
log_level:value("INFO")
|
||||
log_level:value("WARN")
|
||||
log_level:value("ERROR")
|
||||
log_level.default = "WARN"
|
||||
log_level.description = translate(
|
||||
"Sets the logging level. Do not keep the log level set to DEBUG for an extended period of time.")
|
||||
|
||||
-- Log Lines
|
||||
local logLines = section:taboption("log", Value, "log_lines", translate("Display Lines"))
|
||||
logLines.default = "1000"
|
||||
logLines.datatype = "uinteger"
|
||||
logLines.rmempty = false
|
||||
|
||||
-- Button Container (DummyValue to hold all buttons)
|
||||
local button_container = section:taboption("log", DummyValue, "_button_container", translate("Log Actions"))
|
||||
button_container.rawhtml = true
|
||||
|
||||
function button_container.cfgvalue(self, section)
|
||||
return ""
|
||||
end
|
||||
|
||||
function button_container.render(self, section, scope)
|
||||
luci.http.write([[
|
||||
<div class="cbi-value" id="cbi-ua3f-main-_button_container">
|
||||
<label class="cbi-value-title">]] .. translate("Log Management") .. [[</label>
|
||||
<div class="cbi-value-field" style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<input type="button" class="btn cbi-button cbi-button-reset"
|
||||
value="]] .. translate("Clear Logs") .. [[" id="ua3f-clearlog-btn"/>
|
||||
<input type="button" class="btn cbi-button cbi-button-apply"
|
||||
value="]] .. translate("Download Logs") .. [[" id="ua3f-download-btn"/>
|
||||
<input type="button" class="btn cbi-button cbi-button-save"
|
||||
value="]] .. translate("Issue Report") .. [[" id="ua3f-issue-btn"/>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
// Clear Log Button
|
||||
document.getElementById('ua3f-clearlog-btn').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
fetch(']] .. luci.dispatcher.build_url("admin/services/ua3f/clear_log") .. [[', {method: 'POST'})
|
||||
.then(resp => {
|
||||
if (resp.ok) {
|
||||
var textarea = document.getElementById('cbid.ua3f.main.log');
|
||||
if (textarea) textarea.value = "";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Download Log Button
|
||||
document.getElementById('ua3f-download-btn').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
window.location.href = ']] .. luci.dispatcher.build_url("admin/services/ua3f/download_log") .. [[';
|
||||
});
|
||||
|
||||
// Issue Report Button
|
||||
document.getElementById('ua3f-issue-btn').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
window.open('https://github.com/SunBK201/UA3F/issues/new?template=bug-report.md', '_blank');
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
]])
|
||||
end
|
||||
|
||||
return log
|
||||
end
|
||||
|
||||
return M
|
||||
41
openwrt/files/luci/model/cbi/ua3f/others.lua
Normal file
41
openwrt/files/luci/model/cbi/ua3f/others.lua
Normal file
@ -0,0 +1,41 @@
|
||||
local M = {}
|
||||
|
||||
local cbi = require("luci.cbi")
|
||||
local i18n = require("luci.i18n")
|
||||
local utils = require("luci.model.cbi.ua3f.utils")
|
||||
local translate = i18n.translate
|
||||
|
||||
local Flag = cbi.Flag
|
||||
local DummyValue = cbi.DummyValue
|
||||
|
||||
function M.add_others_fields(section)
|
||||
-- TTL Setting
|
||||
local ttl = section:taboption("others", Flag, "set_ttl", translate("Set TTL"))
|
||||
ttl.description = translate("Set the TTL 64 for packets")
|
||||
|
||||
-- TCP Timestamp Deletion
|
||||
local tcpts = section:taboption("others", Flag, "del_tcpts", translate("Delete TCP Timestamps"))
|
||||
tcpts.description = translate("Remove TCP Timestamp option")
|
||||
|
||||
-- TCP Initial Window
|
||||
local tcp_init_window = section:taboption("others", Flag, "set_tcp_init_window", translate("Set TCP Initial Window"))
|
||||
tcp_init_window.description = translate("Set the TCP Initial Window to 65535 for SYN packets")
|
||||
|
||||
-- IP ID Setting
|
||||
local ipid = section:taboption("others", Flag, "set_ipid", translate("Set IP ID"))
|
||||
ipid.description = translate("Set the IP ID to 0 for packets")
|
||||
|
||||
if not utils.nfqueue_exists() then
|
||||
local nfqueue_warning = section:taboption("others", DummyValue, "_others_nfqueue_warning", " ")
|
||||
nfqueue_warning.rawhtml = true
|
||||
nfqueue_warning:depends("del_tcpts", 1)
|
||||
nfqueue_warning:depends("set_tcp_init_window", 1)
|
||||
nfqueue_warning:depends("set_ipid", 1)
|
||||
function nfqueue_warning.cfgvalue(self, section)
|
||||
return "<strong style='color:red;'>" ..
|
||||
translate("Recommend install kmod-nft-queue package for NFQUEUE mode") .. "</strong>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
12
openwrt/files/luci/model/cbi/ua3f/rule.lua
Normal file
12
openwrt/files/luci/model/cbi/ua3f/rule.lua
Normal file
@ -0,0 +1,12 @@
|
||||
local M = {}
|
||||
|
||||
local cbi = require("luci.cbi")
|
||||
|
||||
local DummyValue = cbi.DummyValue
|
||||
|
||||
function M.add_rule_fields(section)
|
||||
local rules = section:taboption("rules", DummyValue, "")
|
||||
rules.template = "ua3f/rules"
|
||||
end
|
||||
|
||||
return M
|
||||
@ -1,6 +1,14 @@
|
||||
-- UA3F Statistics Data Module
|
||||
local M = {}
|
||||
|
||||
local cbi = require("luci.cbi")
|
||||
|
||||
local DummyValue = cbi.DummyValue
|
||||
|
||||
function M.add_statistics_fields(section)
|
||||
local stats = section:taboption("statistics", DummyValue, "")
|
||||
stats.template = "ua3f/statistics"
|
||||
end
|
||||
|
||||
-- Read rewrite statistics from file
|
||||
function M.read_rewrite_stats()
|
||||
local stats = {}
|
||||
|
||||
30
openwrt/files/luci/model/cbi/ua3f/status.lua
Normal file
30
openwrt/files/luci/model/cbi/ua3f/status.lua
Normal file
@ -0,0 +1,30 @@
|
||||
local M = {}
|
||||
|
||||
local cbi = require("luci.cbi")
|
||||
local i18n = require("luci.i18n")
|
||||
local sys = require("luci.sys")
|
||||
local translate = i18n.translate
|
||||
|
||||
local Flag = cbi.Flag
|
||||
local DummyValue = cbi.DummyValue
|
||||
|
||||
function M.add_status_fields(section)
|
||||
-- Enabled Flag
|
||||
section:option(Flag, "enabled", translate("Enabled"))
|
||||
|
||||
-- Running Status Display
|
||||
local running = section:option(DummyValue, "running", translate("Status"))
|
||||
running.rawhtml = true
|
||||
running.cfgvalue = function(self, section)
|
||||
local pid = sys.exec("pidof ua3f")
|
||||
if pid == "" then
|
||||
return "<input disabled type='button' style='opacity: 1;' class='btn cbi-button cbi-button-reset' value='" ..
|
||||
translate("Stop") .. "'/>"
|
||||
else
|
||||
return "<input disabled type='button' style='opacity: 1;' class='btn cbi-button cbi-button-add' value='" ..
|
||||
translate("Running") .. "'/>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
21
openwrt/files/luci/model/cbi/ua3f/utils.lua
Normal file
21
openwrt/files/luci/model/cbi/ua3f/utils.lua
Normal file
@ -0,0 +1,21 @@
|
||||
local M = {}
|
||||
|
||||
local sys = require("luci.sys")
|
||||
|
||||
local function cmd_exists(cmd)
|
||||
return sys.call("command -v " .. cmd .. " >/dev/null 2>&1") == 0
|
||||
end
|
||||
|
||||
function M.nfqueue_exists()
|
||||
local opkg = cmd_exists("opkg") and sys.call("opkg list-installed kmod-nft-queue | grep -q kmod-nft-queue") == 0
|
||||
local apk = cmd_exists("apk") and (sys.call("apk info | grep -q kmod-nft-queue") == 0)
|
||||
return opkg or apk
|
||||
end
|
||||
|
||||
function M.tproxy_exists()
|
||||
local opkg = cmd_exists("opkg") and sys.call("opkg list-installed kmod-nft-tproxy | grep -q kmod-nft-tproxy") == 0
|
||||
local apk = cmd_exists("apk") and (sys.call("apk info | grep -q kmod-nft-tproxy") == 0)
|
||||
return opkg or apk
|
||||
end
|
||||
|
||||
return M
|
||||
Loading…
Reference in New Issue
Block a user