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

409 lines
14 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)
2023-09-22 09:11:34 +08:00
api.set_apply_on_parse(m)
2022-03-11 18:29:27 +08:00
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
2024-03-17 19:17:01 +08:00
local normal_list = {}
local balancing_list = {}
local shunt_list = {}
local iface_list = {}
for k, v in pairs(nodes_table) do
if v.node_type == "normal" then
normal_list[#normal_list + 1] = v
end
if v.protocol and v.protocol == "_balancing" then
balancing_list[#balancing_list + 1] = v
end
if v.protocol and v.protocol == "_shunt" then
shunt_list[#shunt_list + 1] = v
end
if v.protocol and v.protocol == "_iface" then
iface_list[#iface_list + 1] = v
end
end
local socks_list = {}
uci:foreach(appname, "socks", function(s)
if s.enabled == "1" and s.node then
socks_list[#socks_list + 1] = {
id = "Socks_" .. s[".name"],
remark = translate("Socks Config") .. " [" .. s.port .. "端口]"
}
end
end)
2022-03-11 18:29:27 +08:00
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-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")
2024-03-17 19:17:01 +08:00
o = s:taboption("Main", ListValue, 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."))
2023-05-25 23:35:42 +08:00
o:depends(vid .. "-preproxy_enabled", "1")
2024-03-17 19:17:01 +08:00
for k1, v1 in pairs(socks_list) do
o:value(v1.id, v1.remark)
end
2023-05-25 23:35:42 +08:00
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
2024-03-17 19:17:01 +08:00
o = s:taboption("Main", ListValue, node_option, string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", id), e.remarks))
2023-05-25 23:35:42 +08:00
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"
2024-03-17 19:17:01 +08:00
for k1, v1 in pairs(socks_list) do
o:value(v1.id, v1.remark)
end
2023-05-25 23:35:42 +08:00
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"
2024-03-17 19:17:01 +08:00
o = s:taboption("Main", ListValue, vid .. "-" .. id, string.format('* <a style="color:red">%s</a>', translate("Default")))
2023-05-25 23:35:42 +08:00
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"))
2024-03-17 19:17:01 +08:00
for k1, v1 in pairs(socks_list) do
o:value(v1.id, v1.remark)
end
2023-05-25 23:35:42 +08:00
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
2024-03-14 20:28:56 +08:00
o = s:taboption("Main", Flag, "client_proxy", translate("Client Proxy"), translate("When selected, devices in LAN can transparent proxy. Otherwise, it will not be proxy. But you can still use access control to allow the designated device to 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-09-21 23:36:20 +08:00
o:depends({ __hide = true })
2022-03-11 18:29:27 +08:00
2023-09-26 16:23:24 +08:00
o = s:taboption("DNS", ListValue, "remote_dns_detour", translate("Remote DNS Outbound"))
o.default = "remote"
o:value("remote", translate("Remote"))
o:value("direct", translate("Direct"))
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"
2023-09-21 23:36:20 +08:00
o:depends({ __hide = true })
2023-09-04 23:36:20 +08:00
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
2024-03-09 04:14:41 +08:00
o = s:taboption("DNS", Flag, "write_ipset_direct", translate("Direct DNS result write to IPSet"), translate("Perform the matching direct domain name rules into IP to IPSet/NFTSet, and then connect directly (not entering the core). Maybe conflict with some special circumstances."))
o.default = "1"
o.rmempty = false
o = s:taboption("DNS", Button, "clear_ipset", translate("Clear IPSet"), translate("Try this feature if the rule modification does not take effect."))
2023-04-26 16:21:10 +08:00
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