small-package/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua

374 lines
12 KiB
Lua
Raw Normal View History

2023-02-16 23:37:45 +08:00
local api = require "luci.passwall2.api"
2022-03-11 18:29:27 +08:00
local appname = api.appname
local uci = api.uci
local datatypes = api.datatypes
2023-09-06 23:36:47 +08:00
local has_singbox = api.finded_com("singbox")
local has_xray = api.finded_com("xray")
2022-03-11 18:29:27 +08:00
m = Map(appname)
local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do
2023-04-09 23:35:07 +08:00
nodes_table[#nodes_table + 1] = e
2022-03-11 18:29:27 +08:00
end
local doh_validate = function(self, value, t)
2023-04-09 23:35:07 +08:00
if value ~= "" then
local flag = 0
local util = require "luci.util"
local val = util.split(value, ",")
local url = val[1]
val[1] = nil
for i = 1, #val do
local v = val[i]
if v then
if not datatypes.ipmask4(v) then
flag = 1
end
end
end
if flag == 0 then
return value
end
end
return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP"
2022-03-11 18:29:27 +08:00
end
m:append(Template(appname .. "/global/status"))
2023-09-04 23:36:20 +08:00
local global_cfgid = uci:get_all(appname, "@global[0]")[".name"]
2022-03-11 18:29:27 +08:00
s = m:section(TypedSection, "global")
s.anonymous = true
s.addremove = false
s:tab("Main", translate("Main"))
-- [[ Global Settings ]]--
o = s:taboption("Main", Flag, "enabled", translate("Main switch"))
o.rmempty = false
2023-04-10 09:16:48 +08:00
---- Node
node = s:taboption("Main", ListValue, "node", "<a style='color: red'>" .. translate("Node") .. "</a>")
2022-03-11 18:29:27 +08:00
node:value("nil", translate("Close"))
-- 分流
2023-09-05 19:23:30 +08:00
if (has_singbox or has_xray) and #nodes_table > 0 then
2023-04-09 23:35:07 +08:00
local normal_list = {}
2023-05-25 23:35:42 +08:00
local balancing_list = {}
2023-04-09 23:35:07 +08:00
local shunt_list = {}
2023-08-12 09:06:45 +08:00
local iface_list = {}
2023-04-09 23:35:07 +08:00
for k, v in pairs(nodes_table) do
if v.node_type == "normal" then
normal_list[#normal_list + 1] = v
end
2023-05-25 23:35:42 +08:00
if v.protocol and v.protocol == "_balancing" then
balancing_list[#balancing_list + 1] = v
end
2023-04-09 23:35:07 +08:00
if v.protocol and v.protocol == "_shunt" then
shunt_list[#shunt_list + 1] = v
end
2023-08-12 09:06:45 +08:00
if v.protocol and v.protocol == "_iface" then
iface_list[#iface_list + 1] = v
end
2023-04-09 23:35:07 +08:00
end
2023-05-25 23:35:42 +08:00
local function get_cfgvalue(shunt_node_id, option)
return function(self, section)
return m:get(shunt_node_id, option) or "nil"
end
end
local function get_write(shunt_node_id, option)
return function(self, section, value)
m:set(shunt_node_id, option, value)
end
end
if #normal_list > 0 then
for k, v in pairs(shunt_list) do
local vid = v.id
2023-09-05 19:23:30 +08:00
-- shunt node type, Sing-Box or Xray
2023-05-25 23:35:42 +08:00
local type = s:taboption("Main", ListValue, vid .. "-type", translate("Type"))
2023-09-04 23:36:20 +08:00
if has_singbox then
type:value("sing-box", translate("Sing-Box"))
end
2023-05-25 23:35:42 +08:00
if has_xray then
type:value("Xray", translate("Xray"))
end
type.cfgvalue = get_cfgvalue(v.id, "type")
type.write = get_write(v.id, "type")
-- pre-proxy
o = s:taboption("Main", Flag, vid .. "-preproxy_enabled", translate("Preproxy"))
o:depends("node", v.id)
o.rmempty = false
o.cfgvalue = get_cfgvalue(v.id, "preproxy_enabled")
o.write = get_write(v.id, "preproxy_enabled")
o = s:taboption("Main", Value, vid .. "-main_node", string.format('<a style="color:red">%s</a>', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including <code>Default</code>) has a separate switch that controls whether this rule uses the pre-proxy or not."))
o:depends(vid .. "-preproxy_enabled", "1")
for k1, v1 in pairs(balancing_list) do
o:value(v1.id, v1.remark)
end
2023-08-12 09:06:45 +08:00
for k1, v1 in pairs(iface_list) do
o:value(v1.id, v1.remark)
end
2023-05-25 23:35:42 +08:00
for k1, v1 in pairs(normal_list) do
o:value(v1.id, v1.remark)
end
if #o.keylist > 0 then
o.default = o.keylist[1]
end
o.cfgvalue = get_cfgvalue(v.id, "main_node")
o.write = get_write(v.id, "main_node")
2023-09-05 19:23:30 +08:00
if (has_singbox and has_xray) or (v.type == "sing-box" and not has_singbox) or (v.type == "Xray" and not has_xray) then
2023-05-25 23:35:42 +08:00
type:depends("node", v.id)
else
type:depends("node", "hide") --不存在的依赖,即始终隐藏
end
uci:foreach(appname, "shunt_rules", function(e)
local id = e[".name"]
local node_option = vid .. "-" .. id .. "_node"
if id and e.remarks then
o = s:taboption("Main", Value, node_option, string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", id), e.remarks))
o.cfgvalue = get_cfgvalue(v.id, id)
o.write = get_write(v.id, id)
o:depends("node", v.id)
o.default = "nil"
o:value("nil", translate("Close"))
o:value("_default", translate("Default"))
o:value("_direct", translate("Direct Connection"))
o:value("_blackhole", translate("Blackhole"))
local pt = s:taboption("Main", ListValue, vid .. "-".. id .. "_proxy_tag", string.format('* <a style="color:red">%s</a>', e.remarks .. " " .. translate("Preproxy")))
pt.cfgvalue = get_cfgvalue(v.id, id .. "_proxy_tag")
pt.write = get_write(v.id, id .. "_proxy_tag")
pt:value("nil", translate("Close"))
pt:value("main", translate("Preproxy Node"))
pt.default = "nil"
for k1, v1 in pairs(balancing_list) do
o:value(v1.id, v1.remark)
end
2023-08-12 09:06:45 +08:00
for k1, v1 in pairs(iface_list) do
o:value(v1.id, v1.remark)
end
2023-05-25 23:35:42 +08:00
for k1, v1 in pairs(normal_list) do
o:value(v1.id, v1.remark)
pt:depends({ [node_option] = v1.id, [vid .. "-preproxy_enabled"] = "1" })
end
2023-04-09 23:35:07 +08:00
end
2023-05-25 23:35:42 +08:00
end)
local id = "default_node"
o = s:taboption("Main", Value, vid .. "-" .. id, string.format('* <a style="color:red">%s</a>', translate("Default")))
o.cfgvalue = get_cfgvalue(v.id, id)
o.write = get_write(v.id, id)
o:depends("node", v.id)
o.default = "_direct"
o:value("_direct", translate("Direct Connection"))
o:value("_blackhole", translate("Blackhole"))
for k1, v1 in pairs(balancing_list) do
o:value(v1.id, v1.remark)
end
2023-08-12 09:06:45 +08:00
for k1, v1 in pairs(iface_list) do
o:value(v1.id, v1.remark)
end
2023-05-25 23:35:42 +08:00
for k1, v1 in pairs(normal_list) do
o:value(v1.id, v1.remark)
end
local id = "default_proxy_tag"
o = s:taboption("Main", ListValue, vid .. "-" .. id, string.format('* <a style="color:red">%s</a>', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
o.cfgvalue = get_cfgvalue(v.id, id)
o.write = get_write(v.id, id)
o:value("nil", translate("Close"))
o:value("main", translate("Preproxy Node"))
for k1, v1 in pairs(normal_list) do
if v1.protocol ~= "_balancing" then
o:depends({ [vid .. "-default_node"] = v1.id, [vid .. "-preproxy_enabled"] = "1" })
2023-04-09 23:35:07 +08:00
end
end
end
2023-05-25 23:35:42 +08:00
else
local tips = s:taboption("Main", DummyValue, "tips", " ")
tips.rawhtml = true
tips.cfgvalue = function(t, n)
return string.format('<a style="color: red">%s</a>', translate("There are no available nodes, please add or subscribe nodes first."))
2023-04-09 23:35:07 +08:00
end
2023-05-25 23:35:42 +08:00
tips:depends({ node = "nil", ["!reverse"] = true })
for k, v in pairs(shunt_list) do
tips:depends("node", v.id)
2023-04-09 23:35:07 +08:00
end
2023-05-25 23:35:42 +08:00
for k, v in pairs(balancing_list) do
tips:depends("node", v.id)
2023-04-10 09:16:48 +08:00
end
2023-04-09 23:35:07 +08:00
end
2022-03-11 18:29:27 +08:00
end
2022-04-19 07:44:18 +08:00
o = s:taboption("Main", Flag, "localhost_proxy", translate("Localhost Proxy"), translate("When selected, localhost can transparent proxy."))
o.default = "1"
o.rmempty = false
2023-02-08 00:47:38 +08:00
node_socks_port = s:taboption("Main", Value, "node_socks_port", translate("Node") .. " Socks " .. translate("Listen Port"))
node_socks_port.default = 1070
node_socks_port.datatype = "port"
2022-03-11 18:29:27 +08:00
s:tab("DNS", translate("DNS"))
2022-04-12 20:35:28 +08:00
o = s:taboption("DNS", ListValue, "remote_dns_protocol", translate("Remote DNS Protocol"))
o:value("tcp", "TCP")
o:value("doh", "DoH")
2022-04-13 20:35:44 +08:00
o:value("udp", "UDP")
2022-03-11 18:29:27 +08:00
---- DNS Forward
2022-04-12 20:35:28 +08:00
o = s:taboption("DNS", Value, "remote_dns", translate("Remote DNS"))
2022-03-11 18:29:27 +08:00
o.datatype = "or(ipaddr,ipaddrport)"
o.default = "1.1.1.1"
2022-04-12 20:35:28 +08:00
o:value("1.1.1.1", "1.1.1.1 (CloudFlare)")
o:value("1.1.1.2", "1.1.1.2 (CloudFlare-Security)")
o:value("8.8.4.4", "8.8.4.4 (Google)")
o:value("8.8.8.8", "8.8.8.8 (Google)")
o:value("9.9.9.9", "9.9.9.9 (Quad9-Recommended)")
o:value("208.67.220.220", "208.67.220.220 (OpenDNS)")
o:value("208.67.222.222", "208.67.222.222 (OpenDNS)")
o:depends("remote_dns_protocol", "tcp")
2022-04-13 20:35:44 +08:00
o:depends("remote_dns_protocol", "udp")
2022-04-12 20:35:28 +08:00
---- DoH
o = s:taboption("DNS", Value, "remote_dns_doh", translate("Remote DNS DoH"))
o.default = "https://1.1.1.1/dns-query"
o:value("https://1.1.1.1/dns-query", "CloudFlare")
o:value("https://1.1.1.2/dns-query", "CloudFlare-Security")
o:value("https://8.8.4.4/dns-query", "Google 8844")
o:value("https://8.8.8.8/dns-query", "Google 8888")
o:value("https://9.9.9.9/dns-query", "Quad9-Recommended")
o:value("https://208.67.222.222/dns-query", "OpenDNS")
o:value("https://dns.adguard.com/dns-query,176.103.130.130", "AdGuard")
o:value("https://doh.libredns.gr/dns-query,116.202.176.26", "LibreDNS")
o:value("https://doh.libredns.gr/ads,116.202.176.26", "LibreDNS (No Ads)")
o.validate = doh_validate
o:depends("remote_dns_protocol", "doh")
o = s:taboption("DNS", Value, "remote_dns_client_ip", translate("Remote DNS EDNS Client Subnet"))
2022-03-11 18:29:27 +08:00
o.description = translate("Notify the DNS server when the DNS query is notified, the location of the client (cannot be a private IP address).") .. "<br />" ..
2023-04-09 23:35:07 +08:00
translate("This feature requires the DNS server to support the Edns Client Subnet (RFC7871).")
2022-03-11 18:29:27 +08:00
o.datatype = "ipaddr"
2023-04-27 00:22:40 +08:00
o = s:taboption("DNS", Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy."))
o.default = "0"
o.rmempty = false
2023-02-09 09:40:07 +08:00
o = s:taboption("DNS", ListValue, "remote_dns_query_strategy", translate("Remote Query Strategy"))
2022-04-13 20:35:44 +08:00
o.default = "UseIPv4"
o:value("UseIP")
o:value("UseIPv4")
2023-02-09 09:40:07 +08:00
o:value("UseIPv6")
2022-04-13 20:35:44 +08:00
2023-09-04 23:36:20 +08:00
o = s:taboption("DNS", TextValue, "dns_hosts", translate("Domain Override"))
o.rows = 5
o.wrap = "off"
o.remove = function(self, section)
local node_value = node:formvalue(global_cfgid)
2023-09-13 16:22:26 +08:00
if node_value ~= "nil" then
local node_t = m:get(node_value) or {}
if node_t.type == "Xray" then
AbstractValue.remove(self, section)
end
2023-09-04 23:36:20 +08:00
end
end
2022-04-13 20:35:44 +08:00
2023-04-26 16:21:10 +08:00
o = s:taboption("DNS", Button, "clear_ipset", translate("Clear IPSET"), translate("Try this feature if the rule modification does not take effect."))
o.inputstyle = "remove"
function o.write(e, e)
2023-05-25 23:35:42 +08:00
luci.sys.call("[ -n \"$(nft list sets 2>/dev/null | grep \"passwall2_\")\" ] && sh /usr/share/" .. appname .. "/nftables.sh flush_nftset || sh /usr/share/" .. appname .. "/iptables.sh flush_ipset > /dev/null 2>&1 &")
2023-04-26 16:21:10 +08:00
luci.http.redirect(api.url("log"))
end
2023-09-04 23:36:20 +08:00
for k, v in pairs(nodes_table) do
if v.type == "Xray" then
s.fields["remote_dns_client_ip"]:depends({ node = v.id, remote_dns_protocol = "tcp" })
s.fields["remote_dns_client_ip"]:depends({ node = v.id, remote_dns_protocol = "doh" })
s.fields["dns_hosts"]:depends({ node = v.id })
end
end
2022-03-11 18:29:27 +08:00
s:tab("log", translate("Log"))
o = s:taboption("log", Flag, "close_log", translate("Close Node Log"))
o.rmempty = false
loglevel = s:taboption("log", ListValue, "loglevel", translate("Log Level"))
loglevel.default = "warning"
loglevel:value("debug")
loglevel:value("info")
loglevel:value("warning")
loglevel:value("error")
s:tab("faq", "FAQ")
o = s:taboption("faq", DummyValue, "")
o.template = appname .. "/global/faq"
-- [[ Socks Server ]]--
o = s:taboption("Main", Flag, "socks_enabled", "Socks " .. translate("Main switch"))
o.rmempty = false
s = m:section(TypedSection, "socks", translate("Socks Config"))
2023-08-22 16:22:05 +08:00
s.template = "cbi/tblsection"
2022-03-11 18:29:27 +08:00
s.anonymous = true
s.addremove = true
2023-08-22 16:22:05 +08:00
s.extedit = api.url("socks_config", "%s")
2022-03-11 18:29:27 +08:00
function s.create(e, t)
2023-08-22 16:22:05 +08:00
local uuid = api.gen_short_uuid()
t = uuid
TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t))
2022-03-11 18:29:27 +08:00
end
o = s:option(DummyValue, "status", translate("Status"))
o.rawhtml = true
o.cfgvalue = function(t, n)
2023-04-09 23:35:07 +08:00
return string.format('<div class="_status" socks_id="%s"></div>', n)
2022-03-11 18:29:27 +08:00
end
---- Enable
o = s:option(Flag, "enabled", translate("Enable"))
o.default = 1
o.rmempty = false
socks_node = s:option(ListValue, "node", translate("Socks Node"))
2023-02-08 00:47:38 +08:00
local n = 1
2022-03-11 18:29:27 +08:00
uci:foreach(appname, "socks", function(s)
2023-04-09 23:35:07 +08:00
if s[".name"] == section then
return false
end
n = n + 1
2022-03-11 18:29:27 +08:00
end)
o = s:option(Value, "port", "Socks " .. translate("Listen Port"))
o.default = n + 1080
o.datatype = "port"
o.rmempty = false
2023-09-05 19:23:30 +08:00
if has_singbox or has_xray then
2023-04-09 23:35:07 +08:00
o = s:option(Value, "http_port", "HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
o.default = 0
o.datatype = "port"
2022-03-11 18:29:27 +08:00
end
for k, v in pairs(nodes_table) do
2023-04-09 23:35:07 +08:00
node:value(v.id, v["remark"])
if v.type == "Socks" then
2023-09-05 19:23:30 +08:00
if has_singbox or has_xray then
2023-04-09 23:35:07 +08:00
socks_node:value(v.id, v["remark"])
end
else
socks_node:value(v.id, v["remark"])
end
2022-03-11 18:29:27 +08:00
end
m:append(Template(appname .. "/global/footer"))
return m