luci: unified code style (#2395)

* luci: unified code style
- checked newline at end of file
- unified indent
- removed whitespaces at end of line

* luci: change the indentation of lua files to tabs
This commit is contained in:
nftbty 2023-03-22 08:55:34 +08:00 committed by sbwml
parent 5e84915db1
commit 36c6425b3f
38 changed files with 3688 additions and 3687 deletions

View File

@ -22,12 +22,12 @@ s.anonymous = true
s.addremove = true s.addremove = true
s.extedit = api.url("acl_config", "%s") s.extedit = api.url("acl_config", "%s")
function s.create(e, t) function s.create(e, t)
t = TypedSection.create(e, t) t = TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t)) luci.http.redirect(e.extedit:format(t))
end end
function s.remove(e, t) function s.remove(e, t)
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_" .. t .. "*") sys.call("rm -rf /tmp/etc/passwall_tmp/dns_" .. t .. "*")
TypedSection.remove(e, t) TypedSection.remove(e, t)
end end
---- Enable ---- Enable
@ -41,28 +41,28 @@ o.rmempty = true
local mac_t = {} local mac_t = {}
sys.net.mac_hints(function(e, t) sys.net.mac_hints(function(e, t)
mac_t[e] = { mac_t[e] = {
ip = t, ip = t,
mac = e mac = e
} }
end) end)
o = s:option(DummyValue, "sources", translate("Source")) o = s:option(DummyValue, "sources", translate("Source"))
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
local e = '' local e = ''
local v = Value.cfgvalue(t, n) or '' local v = Value.cfgvalue(t, n) or ''
string.gsub(v, '[^' .. " " .. ']+', function(w) string.gsub(v, '[^' .. " " .. ']+', function(w)
local a = w local a = w
if mac_t[w] then if mac_t[w] then
a = a .. ' (' .. mac_t[w].ip .. ')' a = a .. ' (' .. mac_t[w].ip .. ')'
end end
if #e > 0 then if #e > 0 then
e = e .. "<br />" e = e .. "<br />"
end end
e = e .. a e = e .. a
end) end)
return e return e
end end
---- TCP Proxy Mode ---- TCP Proxy Mode
@ -73,10 +73,10 @@ tcp_proxy_mode:value("default", translate("Default"))
tcp_proxy_mode:value("disable", translate("No Proxy")) tcp_proxy_mode:value("disable", translate("No Proxy"))
tcp_proxy_mode:value("global", translate("Global Proxy")) tcp_proxy_mode:value("global", translate("Global Proxy"))
if has_chnlist and global_proxy_mode:find("returnhome") then if has_chnlist and global_proxy_mode:find("returnhome") then
tcp_proxy_mode:value("returnhome", translate("China List")) tcp_proxy_mode:value("returnhome", translate("China List"))
else else
tcp_proxy_mode:value("gfwlist", translate("GFW List")) tcp_proxy_mode:value("gfwlist", translate("GFW List"))
tcp_proxy_mode:value("chnroute", translate("Not China List")) tcp_proxy_mode:value("chnroute", translate("Not China List"))
end end
tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list")) tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
@ -88,10 +88,10 @@ udp_proxy_mode:value("default", translate("Default"))
udp_proxy_mode:value("disable", translate("No Proxy")) udp_proxy_mode:value("disable", translate("No Proxy"))
udp_proxy_mode:value("global", translate("Global Proxy")) udp_proxy_mode:value("global", translate("Global Proxy"))
if has_chnlist and global_proxy_mode:find("returnhome") then if has_chnlist and global_proxy_mode:find("returnhome") then
udp_proxy_mode:value("returnhome", translate("China List")) udp_proxy_mode:value("returnhome", translate("China List"))
else else
udp_proxy_mode:value("gfwlist", translate("GFW List")) udp_proxy_mode:value("gfwlist", translate("GFW List"))
udp_proxy_mode:value("chnroute", translate("Not China List")) udp_proxy_mode:value("chnroute", translate("Not China List"))
end end
udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list")) udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))

View File

@ -9,28 +9,28 @@ m = Map(appname)
local nodes_table = {} local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do for k, e in ipairs(api.get_valid_nodes()) do
nodes_table[#nodes_table + 1] = e nodes_table[#nodes_table + 1] = e
end end
local global_proxy_mode = (m:get("@global[0]", "tcp_proxy_mode") or "") .. (m:get("@global[0]", "udp_proxy_mode") or "") local global_proxy_mode = (m:get("@global[0]", "tcp_proxy_mode") or "") .. (m:get("@global[0]", "udp_proxy_mode") or "")
local dynamicList_write = function(self, section, value) local dynamicList_write = function(self, section, value)
local t = {} local t = {}
local t2 = {} local t2 = {}
if type(value) == "table" then if type(value) == "table" then
local x local x
for _, x in ipairs(value) do for _, x in ipairs(value) do
if x and #x > 0 then if x and #x > 0 then
if not t2[x] then if not t2[x] then
t2[x] = x t2[x] = x
t[#t+1] = x t[#t+1] = x
end end
end end
end end
else else
t = { value } t = { value }
end end
t = table.concat(t, " ") t = table.concat(t, " ")
return DynamicList.write(self, section, t) return DynamicList.write(self, section, t)
end end
@ -51,22 +51,22 @@ o.rmempty = true
local mac_t = {} local mac_t = {}
sys.net.mac_hints(function(e, t) sys.net.mac_hints(function(e, t)
mac_t[#mac_t + 1] = { mac_t[#mac_t + 1] = {
ip = t, ip = t,
mac = e mac = e
} }
end) end)
table.sort(mac_t, function(a,b) table.sort(mac_t, function(a,b)
if #a.ip < #b.ip then if #a.ip < #b.ip then
return true return true
elseif #a.ip == #b.ip then elseif #a.ip == #b.ip then
if a.ip < b.ip then if a.ip < b.ip then
return true return true
else else
return #a.ip < #b.ip return #a.ip < #b.ip
end end
end end
return false return false
end) end)
---- Source ---- Source
@ -80,58 +80,58 @@ sources.description = "<ul><li>" .. translate("Example:")
.. "</li></ul>" .. "</li></ul>"
sources.cast = "string" sources.cast = "string"
for _, key in pairs(mac_t) do for _, key in pairs(mac_t) do
sources:value(key.mac, "%s (%s)" % {key.mac, key.ip}) sources:value(key.mac, "%s (%s)" % {key.mac, key.ip})
end end
sources.cfgvalue = function(self, section) sources.cfgvalue = function(self, section)
local value local value
if self.tag_error[section] then if self.tag_error[section] then
value = self:formvalue(section) value = self:formvalue(section)
else else
value = self.map:get(section, self.option) value = self.map:get(section, self.option)
if type(value) == "string" then if type(value) == "string" then
local value2 = {} local value2 = {}
string.gsub(value, '[^' .. " " .. ']+', function(w) table.insert(value2, w) end) string.gsub(value, '[^' .. " " .. ']+', function(w) table.insert(value2, w) end)
value = value2 value = value2
end end
end end
return value return value
end end
sources.validate = function(self, value, t) sources.validate = function(self, value, t)
local err = {} local err = {}
for _, v in ipairs(value) do for _, v in ipairs(value) do
local flag = false local flag = false
if v:find("ipset:") and v:find("ipset:") == 1 then if v:find("ipset:") and v:find("ipset:") == 1 then
local ipset = v:gsub("ipset:", "") local ipset = v:gsub("ipset:", "")
if ipset and ipset ~= "" then if ipset and ipset ~= "" then
flag = true flag = true
end end
end end
if flag == false and datatypes.macaddr(v) then if flag == false and datatypes.macaddr(v) then
flag = true flag = true
end end
if flag == false and datatypes.ip4addr(v) then if flag == false and datatypes.ip4addr(v) then
flag = true flag = true
end end
if flag == false and api.iprange(v) then if flag == false and api.iprange(v) then
flag = true flag = true
end end
if flag == false then if flag == false then
err[#err + 1] = v err[#err + 1] = v
end end
end end
if #err > 0 then if #err > 0 then
self:add_error(t, "invalid", translate("Not true format, please re-enter!")) self:add_error(t, "invalid", translate("Not true format, please re-enter!"))
for _, v in ipairs(err) do for _, v in ipairs(err) do
self:add_error(t, "invalid", v) self:add_error(t, "invalid", v)
end end
end end
return value return value
end end
sources.write = dynamicList_write sources.write = dynamicList_write
@ -186,10 +186,10 @@ tcp_proxy_mode:value("default", translate("Default"))
tcp_proxy_mode:value("disable", translate("No Proxy")) tcp_proxy_mode:value("disable", translate("No Proxy"))
tcp_proxy_mode:value("global", translate("Global Proxy")) tcp_proxy_mode:value("global", translate("Global Proxy"))
if has_chnlist and global_proxy_mode:find("returnhome") then if has_chnlist and global_proxy_mode:find("returnhome") then
tcp_proxy_mode:value("returnhome", translate("China List")) tcp_proxy_mode:value("returnhome", translate("China List"))
else else
tcp_proxy_mode:value("gfwlist", translate("GFW List")) tcp_proxy_mode:value("gfwlist", translate("GFW List"))
tcp_proxy_mode:value("chnroute", translate("Not China List")) tcp_proxy_mode:value("chnroute", translate("Not China List"))
end end
tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list")) tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
@ -201,10 +201,10 @@ udp_proxy_mode:value("default", translate("Default"))
udp_proxy_mode:value("disable", translate("No Proxy")) udp_proxy_mode:value("disable", translate("No Proxy"))
udp_proxy_mode:value("global", translate("Global Proxy")) udp_proxy_mode:value("global", translate("Global Proxy"))
if has_chnlist and global_proxy_mode:find("returnhome") then if has_chnlist and global_proxy_mode:find("returnhome") then
udp_proxy_mode:value("returnhome", translate("China List")) udp_proxy_mode:value("returnhome", translate("China List"))
else else
udp_proxy_mode:value("gfwlist", translate("GFW List")) udp_proxy_mode:value("gfwlist", translate("GFW List"))
udp_proxy_mode:value("chnroute", translate("Not China List")) udp_proxy_mode:value("chnroute", translate("Not China List"))
end end
udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list")) udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
@ -218,8 +218,8 @@ udp_node:value("default", translate("Default"))
udp_node:value("tcp", translate("Same as the tcp node")) udp_node:value("tcp", translate("Same as the tcp node"))
for k, v in pairs(nodes_table) do for k, v in pairs(nodes_table) do
tcp_node:value(v.id, v["remark"]) tcp_node:value(v.id, v["remark"])
udp_node:value(v.id, v["remark"]) udp_node:value(v.id, v["remark"])
end end
o = s:option(Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature.")) o = s:option(Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
@ -230,10 +230,10 @@ o:depends({ tcp_node = "default", ['!reverse'] = true })
o = s:option(ListValue, "dns_mode", translate("Filter Mode")) o = s:option(ListValue, "dns_mode", translate("Filter Mode"))
o:depends({ tcp_node = "default", ['!reverse'] = true }) o:depends({ tcp_node = "default", ['!reverse'] = true })
if api.is_finded("dns2socks") then if api.is_finded("dns2socks") then
o:value("dns2socks", "dns2socks") o:value("dns2socks", "dns2socks")
end end
if has_xray then if has_xray then
o:value("xray", "Xray") o:value("xray", "Xray")
end end
o = s:option(ListValue, "v2ray_dns_mode", " ") o = s:option(ListValue, "v2ray_dns_mode", " ")
@ -255,40 +255,40 @@ o:depends("dns_mode", "dns2socks")
o:depends("v2ray_dns_mode", "tcp") o:depends("v2ray_dns_mode", "tcp")
if has_v2ray or has_xray then if has_v2ray or has_xray then
o = s:option(Value, "remote_dns_doh", translate("Remote DNS DoH")) o = s:option(Value, "remote_dns_doh", translate("Remote DNS DoH"))
o:value("https://1.1.1.1/dns-query", "CloudFlare") o:value("https://1.1.1.1/dns-query", "CloudFlare")
o:value("https://1.1.1.2/dns-query", "CloudFlare-Security") 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.4.4/dns-query", "Google 8844")
o:value("https://8.8.8.8/dns-query", "Google 8888") 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://9.9.9.9/dns-query", "Quad9-Recommended")
o:value("https://208.67.222.222/dns-query", "OpenDNS") 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://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/dns-query,116.202.176.26", "LibreDNS")
o:value("https://doh.libredns.gr/ads,116.202.176.26", "LibreDNS (No Ads)") o:value("https://doh.libredns.gr/ads,116.202.176.26", "LibreDNS (No Ads)")
o.default = "https://1.1.1.1/dns-query" o.default = "https://1.1.1.1/dns-query"
o.validate = function(self, value, t) o.validate = function(self, value, t)
if value ~= "" then if value ~= "" then
value = api.trim(value) value = api.trim(value)
local flag = 0 local flag = 0
local util = require "luci.util" local util = require "luci.util"
local val = util.split(value, ",") local val = util.split(value, ",")
local url = val[1] local url = val[1]
val[1] = nil val[1] = nil
for i = 1, #val do for i = 1, #val do
local v = val[i] local v = val[i]
if v then if v then
if not api.datatypes.ipmask4(v) then if not api.datatypes.ipmask4(v) then
flag = 1 flag = 1
end end
end end
end end
if flag == 0 then if flag == 0 then
return value return value
end end
end end
return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP" return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP"
end end
o:depends("v2ray_dns_mode", "doh") o:depends("v2ray_dns_mode", "doh")
end end
o = s:option(Value, "dns_client_ip", translate("EDNS Client Subnet")) o = s:option(Value, "dns_client_ip", translate("EDNS Client Subnet"))
@ -296,20 +296,20 @@ o.datatype = "ipaddr"
o:depends("v2ray_dns_mode", "doh") o:depends("v2ray_dns_mode", "doh")
if has_chnlist then if has_chnlist then
when_chnroute_default_dns = s:option(ListValue, "when_chnroute_default_dns", translate("When using the chnroute list the default DNS")) when_chnroute_default_dns = s:option(ListValue, "when_chnroute_default_dns", translate("When using the chnroute list the default DNS"))
when_chnroute_default_dns.default = "direct" when_chnroute_default_dns.default = "direct"
when_chnroute_default_dns:value("remote", translate("Remote DNS")) when_chnroute_default_dns:value("remote", translate("Remote DNS"))
when_chnroute_default_dns:value("direct", translate("Direct DNS")) when_chnroute_default_dns:value("direct", translate("Direct DNS"))
when_chnroute_default_dns.description = "<ul>" when_chnroute_default_dns.description = "<ul>"
.. "<li>" .. translate("Remote DNS can avoid more DNS leaks, but some domestic domain names maybe to proxy!") .. "</li>" .. "<li>" .. translate("Remote DNS can avoid more DNS leaks, but some domestic domain names maybe to proxy!") .. "</li>"
.. "<li>" .. translate("Direct DNS Internet experience may be better, but DNS will be leaked!") .. "</li>" .. "<li>" .. translate("Direct DNS Internet experience may be better, but DNS will be leaked!") .. "</li>"
if api.is_finded("chinadns-ng") then if api.is_finded("chinadns-ng") then
when_chnroute_default_dns:value("chinadns_ng", translate("ChinaDNS-NG")) when_chnroute_default_dns:value("chinadns_ng", translate("ChinaDNS-NG"))
when_chnroute_default_dns.default = "chinadns_ng" when_chnroute_default_dns.default = "chinadns_ng"
end end
when_chnroute_default_dns.description = when_chnroute_default_dns.description .. "</li></ul>" when_chnroute_default_dns.description = when_chnroute_default_dns.description .. "</li></ul>"
when_chnroute_default_dns:depends("tcp_proxy_mode", "chnroute") when_chnroute_default_dns:depends("tcp_proxy_mode", "chnroute")
when_chnroute_default_dns:depends("udp_proxy_mode", "chnroute") when_chnroute_default_dns:depends("udp_proxy_mode", "chnroute")
end end
return m return m

View File

@ -5,24 +5,24 @@ m = Map(appname)
-- [[ App Settings ]]-- -- [[ App Settings ]]--
s = m:section(TypedSection, "global_app", translate("App Update"), s = m:section(TypedSection, "global_app", translate("App Update"),
"<font color='red'>" .. "<font color='red'>" ..
translate("Please confirm that your firmware supports FPU.") .. translate("Please confirm that your firmware supports FPU.") ..
"</font>") "</font>")
s.anonymous = true s.anonymous = true
s:append(Template(appname .. "/app_update/app_version")) s:append(Template(appname .. "/app_update/app_version"))
local k, v local k, v
local com = require "luci.passwall.com" local com = require "luci.passwall.com"
for k, v in pairs(com) do for k, v in pairs(com) do
o = s:option(Value, k:gsub("%-","_") .. "_file", translatef("%s App Path", v.name)) o = s:option(Value, k:gsub("%-","_") .. "_file", translatef("%s App Path", v.name))
o.default = v.default_path or ("/usr/bin/"..k) o.default = v.default_path or ("/usr/bin/"..k)
o.rmempty = false o.rmempty = false
end end
o = s:option(DummyValue, "tips", " ") o = s:option(DummyValue, "tips", " ")
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
return string.format('<font color="red">%s</font>', translate("if you want to run from memory, change the path, /tmp beginning then save the application and update it manually.")) return string.format('<font color="red">%s</font>', translate("if you want to run from memory, change the path, /tmp beginning then save the application and update it manually."))
end end
return m return m

View File

@ -3,7 +3,7 @@ local appname = api.appname
local nodes_table = {} local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do for k, e in ipairs(api.get_valid_nodes()) do
nodes_table[#nodes_table + 1] = e nodes_table[#nodes_table + 1] = e
end end
m = Map(appname) m = Map(appname)
@ -31,21 +31,21 @@ o.default = 3
o = s:option(DynamicList, "tcp_node", "TCP " .. translate("List of backup nodes")) o = s:option(DynamicList, "tcp_node", "TCP " .. translate("List of backup nodes"))
for k, v in pairs(nodes_table) do for k, v in pairs(nodes_table) do
if v.node_type == "normal" then if v.node_type == "normal" then
o:value(v.id, v["remark"]) o:value(v.id, v["remark"])
end end
end end
function o.write(self, section, value) function o.write(self, section, value)
local t = {} local t = {}
local t2 = {} local t2 = {}
if type(value) == "table" then if type(value) == "table" then
local x local x
for _, x in ipairs(value) do for _, x in ipairs(value) do
if x and #x > 0 then if x and #x > 0 then
if not t2[x] then if not t2[x] then
t2[x] = x t2[x] = x
t[#t+1] = x t[#t+1] = x
end end
end end
end end
else else

View File

@ -10,66 +10,66 @@ m = Map(appname)
local nodes_table = {} local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do for k, e in ipairs(api.get_valid_nodes()) do
nodes_table[#nodes_table + 1] = e nodes_table[#nodes_table + 1] = e
end end
local tcp_socks_server = "127.0.0.1" .. ":" .. (uci:get(appname, "@global[0]", "tcp_node_socks_port") or "1070") local tcp_socks_server = "127.0.0.1" .. ":" .. (uci:get(appname, "@global[0]", "tcp_node_socks_port") or "1070")
local socks_table = {} local socks_table = {}
socks_table[#socks_table + 1] = { socks_table[#socks_table + 1] = {
id = tcp_socks_server, id = tcp_socks_server,
remarks = tcp_socks_server .. " - " .. translate("TCP Node") remarks = tcp_socks_server .. " - " .. translate("TCP Node")
} }
uci:foreach(appname, "socks", function(s) uci:foreach(appname, "socks", function(s)
if s.enabled == "1" and s.node then if s.enabled == "1" and s.node then
local id, remarks local id, remarks
for k, n in pairs(nodes_table) do for k, n in pairs(nodes_table) do
if (s.node == n.id) then if (s.node == n.id) then
remarks = n["remark"]; break remarks = n["remark"]; break
end end
end end
id = "127.0.0.1" .. ":" .. s.port id = "127.0.0.1" .. ":" .. s.port
socks_table[#socks_table + 1] = { socks_table[#socks_table + 1] = {
id = id, id = id,
remarks = id .. " - " .. (remarks or translate("Misconfigured")) remarks = id .. " - " .. (remarks or translate("Misconfigured"))
} }
end end
end) end)
local doh_validate = function(self, value, t) local doh_validate = function(self, value, t)
if value ~= "" then if value ~= "" then
value = api.trim(value) value = api.trim(value)
local flag = 0 local flag = 0
local util = require "luci.util" local util = require "luci.util"
local val = util.split(value, ",") local val = util.split(value, ",")
local url = val[1] local url = val[1]
val[1] = nil val[1] = nil
for i = 1, #val do for i = 1, #val do
local v = val[i] local v = val[i]
if v then if v then
if not datatypes.ipmask4(v) then if not datatypes.ipmask4(v) then
flag = 1 flag = 1
end end
end end
end end
if flag == 0 then if flag == 0 then
return value return value
end end
end end
return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP" return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP"
end end
local redir_mode_validate = function(self, value, t) local redir_mode_validate = function(self, value, t)
local tcp_proxy_mode_v = tcp_proxy_mode:formvalue(t) or "" local tcp_proxy_mode_v = tcp_proxy_mode:formvalue(t) or ""
local udp_proxy_mode_v = udp_proxy_mode:formvalue(t) or "" local udp_proxy_mode_v = udp_proxy_mode:formvalue(t) or ""
local localhost_tcp_proxy_mode_v = localhost_tcp_proxy_mode:formvalue(t) or "" local localhost_tcp_proxy_mode_v = localhost_tcp_proxy_mode:formvalue(t) or ""
local localhost_udp_proxy_mode_v = localhost_udp_proxy_mode:formvalue(t) or "" local localhost_udp_proxy_mode_v = localhost_udp_proxy_mode:formvalue(t) or ""
local s = tcp_proxy_mode_v .. udp_proxy_mode_v .. localhost_tcp_proxy_mode_v .. localhost_udp_proxy_mode_v local s = tcp_proxy_mode_v .. udp_proxy_mode_v .. localhost_tcp_proxy_mode_v .. localhost_udp_proxy_mode_v
if s:find("returnhome") then if s:find("returnhome") then
if s:find("chnroute") or s:find("gfwlist") then if s:find("chnroute") or s:find("gfwlist") then
return nil, translate("China list or gfwlist cannot be used together with outside China list!") return nil, translate("China list or gfwlist cannot be used together with outside China list!")
end end
end end
return value return value
end end
m:append(Template(appname .. "/global/status")) m:append(Template(appname .. "/global/status"))
@ -89,80 +89,80 @@ tcp_node = s:taboption("Main", ListValue, "tcp_node", "<a style='color: red'>" .
tcp_node.description = "" tcp_node.description = ""
local current_node = luci.sys.exec(string.format("[ -f '/tmp/etc/%s/id/TCP' ] && echo -n $(cat /tmp/etc/%s/id/TCP)", appname, appname)) local current_node = luci.sys.exec(string.format("[ -f '/tmp/etc/%s/id/TCP' ] && echo -n $(cat /tmp/etc/%s/id/TCP)", appname, appname))
if current_node and current_node ~= "" and current_node ~= "nil" then if current_node and current_node ~= "" and current_node ~= "nil" then
local n = uci:get_all(appname, current_node) local n = uci:get_all(appname, current_node)
if n then if n then
if tonumber(m:get("@auto_switch[0]", "enable") or 0) == 1 then if tonumber(m:get("@auto_switch[0]", "enable") or 0) == 1 then
local remarks = api.get_full_node_remarks(n) local remarks = api.get_full_node_remarks(n)
local url = api.url("node_config", current_node) local url = api.url("node_config", current_node)
tcp_node.description = tcp_node.description .. translatef("Current node: %s", string.format('<a href="%s">%s</a>', url, remarks)) .. "<br />" tcp_node.description = tcp_node.description .. translatef("Current node: %s", string.format('<a href="%s">%s</a>', url, remarks)) .. "<br />"
end end
end end
end end
tcp_node:value("nil", translate("Close")) tcp_node:value("nil", translate("Close"))
-- 分流 -- 分流
if (has_v2ray or has_xray) and #nodes_table > 0 then if (has_v2ray or has_xray) and #nodes_table > 0 then
local normal_list = {} local normal_list = {}
local shunt_list = {} local shunt_list = {}
for k, v in pairs(nodes_table) do for k, v in pairs(nodes_table) do
if v.node_type == "normal" then if v.node_type == "normal" then
normal_list[#normal_list + 1] = v normal_list[#normal_list + 1] = v
end end
if v.protocol and v.protocol == "_shunt" then if v.protocol and v.protocol == "_shunt" then
shunt_list[#shunt_list + 1] = v shunt_list[#shunt_list + 1] = v
end end
end end
for k, v in pairs(shunt_list) do for k, v in pairs(shunt_list) do
uci:foreach(appname, "shunt_rules", function(e) uci:foreach(appname, "shunt_rules", function(e)
local id = e[".name"] local id = e[".name"]
if id and e.remarks then if id and e.remarks then
o = s:taboption("Main", ListValue, v.id .. "." .. id .. "_node", string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", id), e.remarks)) o = s:taboption("Main", ListValue, v.id .. "." .. id .. "_node", string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", id), e.remarks))
o:depends("tcp_node", v.id) o:depends("tcp_node", v.id)
o:value("nil", translate("Close")) o:value("nil", translate("Close"))
o:value("_default", translate("Default")) o:value("_default", translate("Default"))
o:value("_direct", translate("Direct Connection")) o:value("_direct", translate("Direct Connection"))
o:value("_blackhole", translate("Blackhole")) o:value("_blackhole", translate("Blackhole"))
for k1, v1 in pairs(normal_list) do for k1, v1 in pairs(normal_list) do
o:value(v1.id, v1["remark"]) o:value(v1.id, v1["remark"])
end end
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return m:get(v.id, id) or "nil" return m:get(v.id, id) or "nil"
end end
o.write = function(self, section, value) o.write = function(self, section, value)
m:set(v.id, id, value) m:set(v.id, id, value)
end end
end end
end) end)
local id = "default_node" local id = "default_node"
o = s:taboption("Main", ListValue, v.id .. "." .. id, string.format('* <a style="color:red">%s</a>', translate("Default"))) o = s:taboption("Main", ListValue, v.id .. "." .. id, string.format('* <a style="color:red">%s</a>', translate("Default")))
o:depends("tcp_node", v.id) o:depends("tcp_node", v.id)
o:value("_direct", translate("Direct Connection")) o:value("_direct", translate("Direct Connection"))
o:value("_blackhole", translate("Blackhole")) o:value("_blackhole", translate("Blackhole"))
for k1, v1 in pairs(normal_list) do for k1, v1 in pairs(normal_list) do
o:value(v1.id, v1["remark"]) o:value(v1.id, v1["remark"])
end end
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return m:get(v.id, id) or "nil" return m:get(v.id, id) or "nil"
end end
o.write = function(self, section, value) o.write = function(self, section, value)
m:set(v.id, id, value) m:set(v.id, id, value)
end end
local id = "main_node" local id = "main_node"
o = s:taboption("Main", ListValue, v.id .. "." .. 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 = s:taboption("Main", ListValue, v.id .. "." .. 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:depends("tcp_node", v.id) o:depends("tcp_node", v.id)
o:value("nil", translate("Close")) o:value("nil", translate("Close"))
for k1, v1 in pairs(normal_list) do for k1, v1 in pairs(normal_list) do
o:value(v1.id, v1["remark"]) o:value(v1.id, v1["remark"])
end end
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return m:get(v.id, id) or "nil" return m:get(v.id, id) or "nil"
end end
o.write = function(self, section, value) o.write = function(self, section, value)
m:set(v.id, id, value) m:set(v.id, id, value)
end end
end end
end end
udp_node = s:taboption("Main", ListValue, "udp_node", "<a style='color: red'>" .. translate("UDP Node") .. "</a>") udp_node = s:taboption("Main", ListValue, "udp_node", "<a style='color: red'>" .. translate("UDP Node") .. "</a>")
@ -175,9 +175,9 @@ tcp_node_socks_port.datatype = "port"
--[[ --[[
if has_v2ray or has_xray then if has_v2ray or has_xray then
tcp_node_http_port = s:taboption("Main", Value, "tcp_node_http_port", translate("TCP Node") .. " HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use")) tcp_node_http_port = s:taboption("Main", Value, "tcp_node_http_port", translate("TCP Node") .. " HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
tcp_node_http_port.default = 0 tcp_node_http_port.default = 0
tcp_node_http_port.datatype = "port" tcp_node_http_port.datatype = "port"
end end
]]-- ]]--
@ -192,13 +192,13 @@ dns_mode = s:taboption("DNS", ListValue, "dns_mode", translate("Filter Mode"))
dns_mode.rmempty = false dns_mode.rmempty = false
dns_mode:reset_values() dns_mode:reset_values()
if api.is_finded("dns2tcp") then if api.is_finded("dns2tcp") then
dns_mode:value("dns2tcp", translatef("Requery DNS By %s", "TCP")) dns_mode:value("dns2tcp", translatef("Requery DNS By %s", "TCP"))
end end
if api.is_finded("dns2socks") then if api.is_finded("dns2socks") then
dns_mode:value("dns2socks", "dns2socks") dns_mode:value("dns2socks", "dns2socks")
end end
if has_xray then if has_xray then
dns_mode:value("xray", "Xray") dns_mode:value("xray", "Xray")
end end
dns_mode:value("udp", translatef("Requery DNS By %s", "UDP")) dns_mode:value("udp", translatef("Requery DNS By %s", "UDP"))
@ -208,24 +208,24 @@ o:value("doh", "DoH")
o:value("fakedns", "FakeDNS") o:value("fakedns", "FakeDNS")
o:depends("dns_mode", "xray") o:depends("dns_mode", "xray")
o.validate = function(self, value, t) o.validate = function(self, value, t)
if value == "fakedns" then if value == "fakedns" then
local _dns_mode = dns_mode:formvalue(t) local _dns_mode = dns_mode:formvalue(t)
local _tcp_node = tcp_node:formvalue(t) local _tcp_node = tcp_node:formvalue(t)
if m:get(_tcp_node, "type"):lower() ~= _dns_mode then if m:get(_tcp_node, "type"):lower() ~= _dns_mode then
return nil, translatef("TCP node must be '%s' type to use FakeDNS.", _dns_mode) return nil, translatef("TCP node must be '%s' type to use FakeDNS.", _dns_mode)
end end
end end
return value return value
end end
o = s:taboption("DNS", Value, "socks_server", translate("Socks Server"), translate("Make sure socks service is available on this address.")) o = s:taboption("DNS", Value, "socks_server", translate("Socks Server"), translate("Make sure socks service is available on this address."))
for k, v in pairs(socks_table) do o:value(v.id, v.remarks) end for k, v in pairs(socks_table) do o:value(v.id, v.remarks) end
o.default = socks_table[1].id o.default = socks_table[1].id
o.validate = function(self, value, t) o.validate = function(self, value, t)
if not datatypes.ipaddrport(value) then if not datatypes.ipaddrport(value) then
return nil, translate("Socks Server") .. " " .. translate("Not valid IP format, please re-enter!") return nil, translate("Socks Server") .. " " .. translate("Not valid IP format, please re-enter!")
end end
return value return value
end end
o:depends({dns_mode = "dns2socks"}) o:depends({dns_mode = "dns2socks"})
@ -263,7 +263,7 @@ o:depends("v2ray_dns_mode", "doh")
o = s:taboption("DNS", Value, "dns_client_ip", translate("EDNS Client Subnet")) o = s:taboption("DNS", Value, "dns_client_ip", translate("EDNS Client Subnet"))
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 />" .. 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 />" ..
translate("This feature requires the DNS server to support the Edns Client Subnet (RFC7871).") translate("This feature requires the DNS server to support the Edns Client Subnet (RFC7871).")
o.datatype = "ipaddr" o.datatype = "ipaddr"
o:depends("v2ray_dns_mode", "tcp") o:depends("v2ray_dns_mode", "tcp")
o:depends("v2ray_dns_mode", "doh") o:depends("v2ray_dns_mode", "doh")
@ -276,25 +276,25 @@ o:depends({dns_mode = "xray", v2ray_dns_mode = "doh"})
o.rmempty = false o.rmempty = false
if has_chnlist then if has_chnlist then
when_chnroute_default_dns = s:taboption("DNS", ListValue, "when_chnroute_default_dns", translate("When using the chnroute list the default DNS")) when_chnroute_default_dns = s:taboption("DNS", ListValue, "when_chnroute_default_dns", translate("When using the chnroute list the default DNS"))
when_chnroute_default_dns.default = "direct" when_chnroute_default_dns.default = "direct"
when_chnroute_default_dns:value("remote", translate("Remote DNS")) when_chnroute_default_dns:value("remote", translate("Remote DNS"))
when_chnroute_default_dns:value("direct", translate("Direct DNS")) when_chnroute_default_dns:value("direct", translate("Direct DNS"))
when_chnroute_default_dns.description = "<ul>" when_chnroute_default_dns.description = "<ul>"
.. "<li>" .. translate("Remote DNS can avoid more DNS leaks, but some domestic domain names maybe to proxy!") .. "</li>" .. "<li>" .. translate("Remote DNS can avoid more DNS leaks, but some domestic domain names maybe to proxy!") .. "</li>"
.. "<li>" .. translate("Direct DNS Internet experience may be better, but DNS will be leaked!") .. "</li>" .. "<li>" .. translate("Direct DNS Internet experience may be better, but DNS will be leaked!") .. "</li>"
if api.is_finded("chinadns-ng") then if api.is_finded("chinadns-ng") then
when_chnroute_default_dns:value("chinadns_ng", translate("ChinaDNS-NG")) when_chnroute_default_dns:value("chinadns_ng", translate("ChinaDNS-NG"))
when_chnroute_default_dns.default = "chinadns_ng" when_chnroute_default_dns.default = "chinadns_ng"
end end
when_chnroute_default_dns.description = when_chnroute_default_dns.description .. "</li></ul>" when_chnroute_default_dns.description = when_chnroute_default_dns.description .. "</li></ul>"
end end
o = s:taboption("DNS", Button, "clear_ipset", translate("Clear IPSET"), translate("Try this feature if the rule modification does not take effect.")) 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" o.inputstyle = "remove"
function o.write(e, e) function o.write(e, e)
luci.sys.call("[ -n \"$(nft list sets 2>/dev/null | grep \"gfwlist\")\" ] && /usr/share/" .. appname .. "/nftables.sh flush_nftset || /usr/share/" .. appname .. "/iptables.sh flush_ipset > /dev/null 2>&1 &") luci.sys.call("[ -n \"$(nft list sets 2>/dev/null | grep \"gfwlist\")\" ] && /usr/share/" .. appname .. "/nftables.sh flush_nftset || /usr/share/" .. appname .. "/iptables.sh flush_ipset > /dev/null 2>&1 &")
luci.http.redirect(api.url("log")) luci.http.redirect(api.url("log"))
end end
s:tab("Proxy", translate("Mode")) s:tab("Proxy", translate("Mode"))
@ -306,7 +306,7 @@ tcp_proxy_mode:value("global", translate("Global Proxy"))
tcp_proxy_mode:value("gfwlist", translate("GFW List")) tcp_proxy_mode:value("gfwlist", translate("GFW List"))
tcp_proxy_mode:value("chnroute", translate("Not China List")) tcp_proxy_mode:value("chnroute", translate("Not China List"))
if has_chnlist then if has_chnlist then
tcp_proxy_mode:value("returnhome", translate("China List")) tcp_proxy_mode:value("returnhome", translate("China List"))
end end
tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list")) tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
tcp_proxy_mode.default = "chnroute" tcp_proxy_mode.default = "chnroute"
@ -319,7 +319,7 @@ udp_proxy_mode:value("global", translate("Global Proxy"))
udp_proxy_mode:value("gfwlist", translate("GFW List")) udp_proxy_mode:value("gfwlist", translate("GFW List"))
udp_proxy_mode:value("chnroute", translate("Not China List")) udp_proxy_mode:value("chnroute", translate("Not China List"))
if has_chnlist then if has_chnlist then
udp_proxy_mode:value("returnhome", translate("China List")) udp_proxy_mode:value("returnhome", translate("China List"))
end end
udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list")) udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
udp_proxy_mode.default = "chnroute" udp_proxy_mode.default = "chnroute"
@ -332,7 +332,7 @@ localhost_tcp_proxy_mode:value("global", translate("Global Proxy"))
localhost_tcp_proxy_mode:value("gfwlist", translate("GFW List")) localhost_tcp_proxy_mode:value("gfwlist", translate("GFW List"))
localhost_tcp_proxy_mode:value("chnroute", translate("Not China List")) localhost_tcp_proxy_mode:value("chnroute", translate("Not China List"))
if has_chnlist then if has_chnlist then
localhost_tcp_proxy_mode:value("returnhome", translate("China List")) localhost_tcp_proxy_mode:value("returnhome", translate("China List"))
end end
localhost_tcp_proxy_mode:value("disable", translate("No Proxy")) localhost_tcp_proxy_mode:value("disable", translate("No Proxy"))
localhost_tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list")) localhost_tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
@ -346,7 +346,7 @@ localhost_udp_proxy_mode:value("global", translate("Global Proxy"))
localhost_udp_proxy_mode:value("gfwlist", translate("GFW List")) localhost_udp_proxy_mode:value("gfwlist", translate("GFW List"))
localhost_udp_proxy_mode:value("chnroute", translate("Not China List")) localhost_udp_proxy_mode:value("chnroute", translate("Not China List"))
if has_chnlist then if has_chnlist then
localhost_udp_proxy_mode:value("returnhome", translate("China List")) localhost_udp_proxy_mode:value("returnhome", translate("China List"))
end end
localhost_udp_proxy_mode:value("disable", translate("No Proxy")) localhost_udp_proxy_mode:value("disable", translate("No Proxy"))
localhost_udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list")) localhost_udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
@ -356,7 +356,7 @@ localhost_udp_proxy_mode.validate = redir_mode_validate
tips = s:taboption("Proxy", DummyValue, "tips", " ") tips = s:taboption("Proxy", DummyValue, "tips", " ")
tips.rawhtml = true tips.rawhtml = true
tips.cfgvalue = function(t, n) tips.cfgvalue = function(t, n)
return string.format('<a style="color: red" href="%s">%s</a>', api.url("acl"), translate("Want different devices to use different proxy modes/ports/nodes? Please use access control.")) return string.format('<a style="color: red" href="%s">%s</a>', api.url("acl"), translate("Want different devices to use different proxy modes/ports/nodes? Please use access control."))
end end
s:tab("log", translate("Log")) s:tab("log", translate("Log"))
@ -395,13 +395,13 @@ s.anonymous = true
s.addremove = true s.addremove = true
s.template = "cbi/tblsection" s.template = "cbi/tblsection"
function s.create(e, t) function s.create(e, t)
TypedSection.create(e, api.gen_uuid()) TypedSection.create(e, api.gen_uuid())
end end
o = s:option(DummyValue, "status", translate("Status")) o = s:option(DummyValue, "status", translate("Status"))
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
return string.format('<div class="_status" socks_id="%s"></div>', n) return string.format('<div class="_status" socks_id="%s"></div>', n)
end end
---- Enable ---- Enable
@ -413,10 +413,10 @@ socks_node = s:option(ListValue, "node", translate("Socks Node"))
local n = 1 local n = 1
uci:foreach(appname, "socks", function(s) uci:foreach(appname, "socks", function(s)
if s[".name"] == section then if s[".name"] == section then
return false return false
end end
n = n + 1 n = n + 1
end) end)
o = s:option(Value, "port", "Socks " .. translate("Listen Port")) o = s:option(Value, "port", "Socks " .. translate("Listen Port"))
@ -425,21 +425,21 @@ o.datatype = "port"
o.rmempty = false o.rmempty = false
if has_v2ray or has_xray then if has_v2ray or has_xray then
o = s:option(Value, "http_port", "HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use")) o = s:option(Value, "http_port", "HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
o.default = 0 o.default = 0
o.datatype = "port" o.datatype = "port"
end end
for k, v in pairs(nodes_table) do for k, v in pairs(nodes_table) do
tcp_node:value(v.id, v["remark"]) tcp_node:value(v.id, v["remark"])
udp_node:value(v.id, v["remark"]) udp_node:value(v.id, v["remark"])
if v.type == "Socks" then if v.type == "Socks" then
if has_v2ray or has_xray then if has_v2ray or has_xray then
socks_node:value(v.id, v["remark"]) socks_node:value(v.id, v["remark"])
end end
else else
socks_node:value(v.id, v["remark"]) socks_node:value(v.id, v["remark"])
end end
end end
m:append(Template(appname .. "/global/footer")) m:append(Template(appname .. "/global/footer"))

View File

@ -6,13 +6,13 @@ local datatypes = api.datatypes
local nodes_table = {} local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do for k, e in ipairs(api.get_valid_nodes()) do
if e.node_type == "normal" then if e.node_type == "normal" then
nodes_table[#nodes_table + 1] = { nodes_table[#nodes_table + 1] = {
id = e[".name"], id = e[".name"],
obj = e, obj = e,
remarks = e["remark"] remarks = e["remark"]
} }
end end
end end
m = Map(appname) m = Map(appname)
@ -41,31 +41,31 @@ o:depends("balancing_enable", true)
---- Console Port ---- Console Port
o = s:option(Value, "console_port", translate("Console Port"), translate( o = s:option(Value, "console_port", translate("Console Port"), translate(
"In the browser input routing IP plus port access, such as:192.168.1.1:1188")) "In the browser input routing IP plus port access, such as:192.168.1.1:1188"))
o.default = "1188" o.default = "1188"
o:depends("balancing_enable", true) o:depends("balancing_enable", true)
-- [[ Balancing Settings ]]-- -- [[ Balancing Settings ]]--
s = m:section(TypedSection, "haproxy_config", "", s = m:section(TypedSection, "haproxy_config", "",
"<font color='red'>" .. "<font color='red'>" ..
translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") .. translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") ..
"\n" .. translate("Note that the node configuration parameters for load balancing must be consistent, otherwise problems can arise!") .. "\n" .. translate("Note that the node configuration parameters for load balancing must be consistent, otherwise problems can arise!") ..
"</font>") "</font>")
s.template = "cbi/tblsection" s.template = "cbi/tblsection"
s.sortable = true s.sortable = true
s.anonymous = true s.anonymous = true
s.addremove = true s.addremove = true
s.create = function(e, t) s.create = function(e, t)
TypedSection.create(e, api.gen_uuid()) TypedSection.create(e, api.gen_uuid())
end end
s.remove = function(self, section) s.remove = function(self, section)
for k, v in pairs(self.children) do for k, v in pairs(self.children) do
v.rmempty = true v.rmempty = true
v.validate = nil v.validate = nil
end end
TypedSection.remove(self, section) TypedSection.remove(self, section)
end end
---- Enable ---- Enable
@ -78,18 +78,18 @@ o = s:option(Value, "lbss", translate("Node Address"))
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
o.rmempty = false o.rmempty = false
o.validate = function(self, value) o.validate = function(self, value)
if not value then return nil end if not value then return nil end
local t = m:get(value) or nil local t = m:get(value) or nil
if t and t[".type"] == "nodes" then if t and t[".type"] == "nodes" then
return value return value
end end
if datatypes.hostport(value) or datatypes.ip4addrport(value) then if datatypes.hostport(value) or datatypes.ip4addrport(value) then
return value return value
end end
if api.is_ipv6addrport(value) then if api.is_ipv6addrport(value) then
return value return value
end end
return nil, value return nil, value
end end
---- Haproxy Port ---- Haproxy Port

View File

@ -3,53 +3,53 @@ local appname = api.appname
local uci = api.uci local uci = api.uci
if not arg[1] or not uci:get(appname, arg[1]) then if not arg[1] or not uci:get(appname, arg[1]) then
luci.http.redirect(api.url("node_list")) luci.http.redirect(api.url("node_list"))
end end
local ss_encrypt_method_list = { local ss_encrypt_method_list = {
"rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr",
"aes-192-ctr", "aes-256-ctr", "bf-cfb", "salsa20", "chacha20", "chacha20-ietf", "aes-192-ctr", "aes-256-ctr", "bf-cfb", "salsa20", "chacha20", "chacha20-ietf",
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305" "xchacha20-ietf-poly1305"
} }
local ss_rust_encrypt_method_list = { local ss_rust_encrypt_method_list = {
"plain", "none", "plain", "none",
"aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
} }
local ssr_encrypt_method_list = { local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb", "none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
"aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
"cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20", "cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20",
"chacha20-ietf" "chacha20-ietf"
} }
local ssr_protocol_list = { local ssr_protocol_list = {
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple", "origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5", "auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
"auth_chain_d", "auth_chain_e", "auth_chain_f" "auth_chain_d", "auth_chain_e", "auth_chain_f"
} }
local ssr_obfs_list = { local ssr_obfs_list = {
"plain", "http_simple", "http_post", "random_head", "tls_simple", "plain", "http_simple", "http_post", "random_head", "tls_simple",
"tls1.0_session_auth", "tls1.2_ticket_auth" "tls1.0_session_auth", "tls1.2_ticket_auth"
} }
local v_ss_encrypt_method_list = { local v_ss_encrypt_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305" "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305"
} }
local x_ss_encrypt_method_list = { local x_ss_encrypt_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
} }
local security_list = {"none", "auto", "aes-128-gcm", "chacha20-poly1305", "zero"} local security_list = {"none", "auto", "aes-128-gcm", "chacha20-poly1305", "zero"}
local header_type_list = { local header_type_list = {
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard" "none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
} }
local encrypt_methods_ss_aead = { local encrypt_methods_ss_aead = {
"chacha20-ietf-poly1305", "chacha20-ietf-poly1305",
@ -75,42 +75,42 @@ remarks.rmempty = false
type = s:option(ListValue, "type", translate("Type")) type = s:option(ListValue, "type", translate("Type"))
if api.is_finded("ipt2socks") then if api.is_finded("ipt2socks") then
type:value("Socks", translate("Socks")) type:value("Socks", translate("Socks"))
end end
if api.is_finded("ss-redir") then if api.is_finded("ss-redir") then
type:value("SS", translate("Shadowsocks Libev")) type:value("SS", translate("Shadowsocks Libev"))
end end
if api.is_finded("sslocal") then if api.is_finded("sslocal") then
type:value("SS-Rust", translate("Shadowsocks Rust")) type:value("SS-Rust", translate("Shadowsocks Rust"))
end end
if api.is_finded("ssr-redir") then if api.is_finded("ssr-redir") then
type:value("SSR", translate("ShadowsocksR Libev")) type:value("SSR", translate("ShadowsocksR Libev"))
end end
if api.is_finded("v2ray") then if api.is_finded("v2ray") then
type:value("V2ray", translate("V2ray")) type:value("V2ray", translate("V2ray"))
end end
if api.is_finded("xray") then if api.is_finded("xray") then
type:value("Xray", translate("Xray")) type:value("Xray", translate("Xray"))
end end
if api.is_finded("brook") then if api.is_finded("brook") then
type:value("Brook", translate("Brook")) type:value("Brook", translate("Brook"))
end end
--[[ --[[
if api.is_finded("trojan-plus") or api.is_finded("trojan") then if api.is_finded("trojan-plus") or api.is_finded("trojan") then
type:value("Trojan", translate("Trojan")) type:value("Trojan", translate("Trojan"))
end end
]]-- ]]--
if api.is_finded("trojan-plus") then if api.is_finded("trojan-plus") then
type:value("Trojan-Plus", translate("Trojan-Plus")) type:value("Trojan-Plus", translate("Trojan-Plus"))
end end
if api.is_finded("trojan-go") then if api.is_finded("trojan-go") then
type:value("Trojan-Go", translate("Trojan-Go")) type:value("Trojan-Go", translate("Trojan-Go"))
end end
if api.is_finded("naive") then if api.is_finded("naive") then
type:value("Naiveproxy", translate("NaiveProxy")) type:value("Naiveproxy", translate("NaiveProxy"))
end end
if api.is_finded("hysteria") then if api.is_finded("hysteria") then
type:value("Hysteria", translate("Hysteria")) type:value("Hysteria", translate("Hysteria"))
end end
protocol = s:option(ListValue, "protocol", translate("Protocol")) protocol = s:option(ListValue, "protocol", translate("Protocol"))
@ -133,12 +133,12 @@ iface:depends("protocol", "_iface")
local nodes_table = {} local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do for k, e in ipairs(api.get_valid_nodes()) do
if e.node_type == "normal" then if e.node_type == "normal" then
nodes_table[#nodes_table + 1] = { nodes_table[#nodes_table + 1] = {
id = e[".name"], id = e[".name"],
remarks = e["remark"] remarks = e["remark"]
} }
end end
end end
-- 负载均衡列表 -- 负载均衡列表
@ -148,33 +148,33 @@ balancing_node:depends("protocol", "_balancing")
-- 分流 -- 分流
uci:foreach(appname, "shunt_rules", function(e) uci:foreach(appname, "shunt_rules", function(e)
if e[".name"] and e.remarks then if e[".name"] and e.remarks then
o = s:option(ListValue, e[".name"], string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", e[".name"]), e.remarks)) o = s:option(ListValue, e[".name"], string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", e[".name"]), e.remarks))
o:value("nil", translate("Close")) o:value("nil", translate("Close"))
o:value("_default", translate("Default")) o:value("_default", translate("Default"))
o:value("_direct", translate("Direct Connection")) o:value("_direct", translate("Direct Connection"))
o:value("_blackhole", translate("Blackhole")) o:value("_blackhole", translate("Blackhole"))
o:depends("protocol", "_shunt") o:depends("protocol", "_shunt")
if #nodes_table > 0 then if #nodes_table > 0 then
_proxy_tag = s:option(ListValue, e[".name"] .. "_proxy_tag", string.format('* <a style="color:red">%s</a>', e.remarks .. " " .. translate("Preproxy"))) _proxy_tag = s:option(ListValue, e[".name"] .. "_proxy_tag", string.format('* <a style="color:red">%s</a>', e.remarks .. " " .. translate("Preproxy")))
_proxy_tag:value("nil", translate("Close")) _proxy_tag:value("nil", translate("Close"))
_proxy_tag:value("default", translate("Default")) _proxy_tag:value("default", translate("Default"))
_proxy_tag:value("main", translate("Default Preproxy")) _proxy_tag:value("main", translate("Default Preproxy"))
_proxy_tag.default = "nil" _proxy_tag.default = "nil"
for k, v in pairs(nodes_table) do for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks) o:value(v.id, v.remarks)
_proxy_tag:depends(e[".name"], v.id) _proxy_tag:depends(e[".name"], v.id)
end end
end end
end end
end) end)
shunt_tips = s:option(DummyValue, "shunt_tips", " ") shunt_tips = s:option(DummyValue, "shunt_tips", " ")
shunt_tips.rawhtml = true shunt_tips.rawhtml = true
shunt_tips.cfgvalue = function(t, n) shunt_tips.cfgvalue = function(t, n)
return string.format('<a style="color: red" href="../rule">%s</a>', translate("No shunt rules? Click me to go to add.")) return string.format('<a style="color: red" href="../rule">%s</a>', translate("No shunt rules? Click me to go to add."))
end end
shunt_tips:depends("protocol", "_shunt") shunt_tips:depends("protocol", "_shunt")
@ -185,12 +185,12 @@ for k, v in pairs(nodes_table) do default_node:value(v.id, v.remarks) end
default_node:depends("protocol", "_shunt") default_node:depends("protocol", "_shunt")
if #nodes_table > 0 then if #nodes_table > 0 then
o = s:option(ListValue, "main_node", 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 = s:option(ListValue, "main_node", 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:value("nil", translate("Close")) o:value("nil", translate("Close"))
for k, v in pairs(nodes_table) do for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks) o:value(v.id, v.remarks)
o:depends("default_node", v.id) o:depends("default_node", v.id)
end end
end end
dialerProxy = s:option(Flag, "dialerProxy", translate("dialerProxy")) dialerProxy = s:option(Flag, "dialerProxy", translate("dialerProxy"))
@ -504,13 +504,13 @@ uuid:depends({ type = "Xray", protocol = "vless" })
tls = s:option(Flag, "tls", translate("TLS")) tls = s:option(Flag, "tls", translate("TLS"))
tls.default = 0 tls.default = 0
tls.validate = function(self, value, t) tls.validate = function(self, value, t)
if value then if value then
local type = type:formvalue(t) or "" local type = type:formvalue(t) or ""
if value == "0" and (type == "Trojan" or type == "Trojan-Plus") then if value == "0" and (type == "Trojan" or type == "Trojan-Plus") then
return nil, translate("Original Trojan only supported 'tls', please choose 'tls'.") return nil, translate("Original Trojan only supported 'tls', please choose 'tls'.")
end end
return value return value
end end
end end
tls:depends({ type = "V2ray", protocol = "vmess" }) tls:depends({ type = "V2ray", protocol = "vmess" })
tls:depends({ type = "V2ray", protocol = "vless" }) tls:depends({ type = "V2ray", protocol = "vless" })
@ -926,11 +926,11 @@ hysteria_disable_mtu_discovery = s:option(Flag, "hysteria_disable_mtu_discovery"
hysteria_disable_mtu_discovery:depends("type", "Hysteria") hysteria_disable_mtu_discovery:depends("type", "Hysteria")
protocol.validate = function(self, value) protocol.validate = function(self, value)
if value == "_shunt" or value == "_balancing" then if value == "_shunt" or value == "_balancing" then
address.rmempty = true address.rmempty = true
port.rmempty = true port.rmempty = true
end end
return value return value
end end
return m return m

View File

@ -26,104 +26,104 @@ s.addremove = true
s.template = "cbi/tblsection" s.template = "cbi/tblsection"
s.extedit = api.url("node_config", "%s") s.extedit = api.url("node_config", "%s")
function s.create(e, t) function s.create(e, t)
local uuid = api.gen_uuid() local uuid = api.gen_uuid()
t = uuid t = uuid
TypedSection.create(e, t) TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t)) luci.http.redirect(e.extedit:format(t))
end end
function s.remove(e, t) function s.remove(e, t)
m.uci:foreach(appname, "socks", function(s) m.uci:foreach(appname, "socks", function(s)
if s["node"] == t then if s["node"] == t then
m:del(s[".name"]) m:del(s[".name"])
end end
end) end)
m.uci:foreach(appname, "haproxy_config", function(s) m.uci:foreach(appname, "haproxy_config", function(s)
if s["lbss"] and s["lbss"] == t then if s["lbss"] and s["lbss"] == t then
m:del(s[".name"]) m:del(s[".name"])
end end
end) end)
m.uci:foreach(appname, "acl_rule", function(s) m.uci:foreach(appname, "acl_rule", function(s)
if s["tcp_node"] and s["tcp_node"] == t then if s["tcp_node"] and s["tcp_node"] == t then
m:set(s[".name"], "tcp_node", "default") m:set(s[".name"], "tcp_node", "default")
end end
if s["udp_node"] and s["udp_node"] == t then if s["udp_node"] and s["udp_node"] == t then
m:set(s[".name"], "udp_node", "default") m:set(s[".name"], "udp_node", "default")
end end
end) end)
for k, v in ipairs(m:get("@auto_switch[0]", "tcp_node") or {}) do for k, v in ipairs(m:get("@auto_switch[0]", "tcp_node") or {}) do
if v and v == t then if v and v == t then
sys.call(string.format("uci -q del_list %s.@auto_switch[0].tcp_node='%s'", appname, v)) sys.call(string.format("uci -q del_list %s.@auto_switch[0].tcp_node='%s'", appname, v))
end end
end end
TypedSection.remove(e, t) TypedSection.remove(e, t)
local new_node = "nil" local new_node = "nil"
local node0 = m:get("@nodes[0]") or nil local node0 = m:get("@nodes[0]") or nil
if node0 then if node0 then
new_node = node0[".name"] new_node = node0[".name"]
end end
if (m:get("@global[0]", "tcp_node") or "nil") == t then if (m:get("@global[0]", "tcp_node") or "nil") == t then
m:set('@global[0]', "tcp_node", new_node) m:set('@global[0]', "tcp_node", new_node)
end end
if (m:get("@global[0]", "udp_node") or "nil") == t then if (m:get("@global[0]", "udp_node") or "nil") == t then
m:set('@global[0]', "udp_node", new_node) m:set('@global[0]', "udp_node", new_node)
end end
end end
s.sortable = true s.sortable = true
-- 简洁模式 -- 简洁模式
o = s:option(DummyValue, "add_from", "") o = s:option(DummyValue, "add_from", "")
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
local v = Value.cfgvalue(t, n) local v = Value.cfgvalue(t, n)
if v and v ~= '' then if v and v ~= '' then
local group = m:get(n, "group") or "" local group = m:get(n, "group") or ""
if group ~= "" then if group ~= "" then
v = v .. " " .. group v = v .. " " .. group
end end
return v return v
else else
return '' return ''
end end
end end
o = s:option(DummyValue, "remarks", translate("Remarks")) o = s:option(DummyValue, "remarks", translate("Remarks"))
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
local str = "" local str = ""
local is_sub = m:get(n, "is_sub") or "" local is_sub = m:get(n, "is_sub") or ""
local group = m:get(n, "group") or "" local group = m:get(n, "group") or ""
local remarks = m:get(n, "remarks") or "" local remarks = m:get(n, "remarks") or ""
local type = m:get(n, "type") or "" local type = m:get(n, "type") or ""
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.type' value='%s'/>", appname, n, type) str = str .. string.format("<input type='hidden' id='cbid.%s.%s.type' value='%s'/>", appname, n, type)
if type == "V2ray" or type == "Xray" then if type == "V2ray" or type == "Xray" then
local protocol = m:get(n, "protocol") local protocol = m:get(n, "protocol")
if protocol == "_balancing" then if protocol == "_balancing" then
protocol = translate("Balancing") protocol = translate("Balancing")
elseif protocol == "_shunt" then elseif protocol == "_shunt" then
protocol = translate("Shunt") protocol = translate("Shunt")
elseif protocol == "vmess" then elseif protocol == "vmess" then
protocol = "VMess" protocol = "VMess"
elseif protocol == "vless" then elseif protocol == "vless" then
protocol = "VLESS" protocol = "VLESS"
else else
protocol = protocol:gsub("^%l",string.upper) protocol = protocol:gsub("^%l",string.upper)
end end
type = type .. " " .. protocol type = type .. " " .. protocol
end end
local address = m:get(n, "address") or "" local address = m:get(n, "address") or ""
local port = m:get(n, "port") or "" local port = m:get(n, "port") or ""
str = str .. translate(type) .. "" .. remarks str = str .. translate(type) .. "" .. remarks
if address ~= "" and port ~= "" then if address ~= "" and port ~= "" then
if nodes_ping:find("info") then if nodes_ping:find("info") then
if datatypes.ip6addr(address) then if datatypes.ip6addr(address) then
str = str .. string.format("[%s]:%s", address, port) str = str .. string.format("[%s]:%s", address, port)
else else
str = str .. string.format("%s:%s", address, port) str = str .. string.format("%s:%s", address, port)
end end
end end
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.address' value='%s'/>", appname, n, address) str = str .. string.format("<input type='hidden' id='cbid.%s.%s.address' value='%s'/>", appname, n, address)
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.port' value='%s'/>", appname, n, port) str = str .. string.format("<input type='hidden' id='cbid.%s.%s.port' value='%s'/>", appname, n, port)
end end
return str return str
end end
---- Ping ---- Ping
@ -131,19 +131,19 @@ o = s:option(DummyValue, "ping")
o.width = "8%" o.width = "8%"
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
local result = "---" local result = "---"
if not nodes_ping:find("auto_ping") then if not nodes_ping:find("auto_ping") then
result = string.format('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'%s\',this)">Ping</a></span>', n) result = string.format('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'%s\',this)">Ping</a></span>', n)
else else
result = string.format('<span class="ping_value" cbiid="%s">---</span>', n) result = string.format('<span class="ping_value" cbiid="%s">---</span>', n)
end end
return result return result
end end
o = s:option(DummyValue, "_url_test") o = s:option(DummyValue, "_url_test")
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
return string.format('<input type="button" class="cbi-button" value="%s" onclick="javascript:urltest_node(\'%s\',this)"', translate("Availability test"), n) return string.format('<input type="button" class="cbi-button" value="%s" onclick="javascript:urltest_node(\'%s\',this)"', translate("Availability test"), n)
end end
m:append(Template(appname .. "/node_list/node_list")) m:append(Template(appname .. "/node_list/node_list"))

View File

@ -9,24 +9,24 @@ local has_trojan_go = api.is_finded("trojan-go")
local ss_aead_type = {} local ss_aead_type = {}
local trojan_type = {} local trojan_type = {}
if has_ss then if has_ss then
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-libev" ss_aead_type[#ss_aead_type + 1] = "shadowsocks-libev"
end end
if has_ss_rust then if has_ss_rust then
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-rust" ss_aead_type[#ss_aead_type + 1] = "shadowsocks-rust"
end end
if has_trojan_plus then if has_trojan_plus then
trojan_type[#trojan_type + 1] = "trojan-plus" trojan_type[#trojan_type + 1] = "trojan-plus"
end end
if has_v2ray then if has_v2ray then
trojan_type[#trojan_type + 1] = "v2ray" trojan_type[#trojan_type + 1] = "v2ray"
ss_aead_type[#ss_aead_type + 1] = "v2ray" ss_aead_type[#ss_aead_type + 1] = "v2ray"
end end
if has_xray then if has_xray then
trojan_type[#trojan_type + 1] = "xray" trojan_type[#trojan_type + 1] = "xray"
ss_aead_type[#ss_aead_type + 1] = "xray" ss_aead_type[#ss_aead_type + 1] = "xray"
end end
if has_trojan_go then if has_trojan_go then
trojan_type[#trojan_type + 1] = "trojan-go" trojan_type[#trojan_type + 1] = "trojan-go"
end end
m = Map(appname) m = Map(appname)
@ -47,31 +47,31 @@ o = s:option(DynamicList, "filter_discard_list", translate("Discard List"))
o = s:option(DynamicList, "filter_keep_list", translate("Keep List")) o = s:option(DynamicList, "filter_keep_list", translate("Keep List"))
if #ss_aead_type > 0 then if #ss_aead_type > 0 then
o = s:option(ListValue, "ss_aead_type", translate("SS AEAD Node Use Type")) o = s:option(ListValue, "ss_aead_type", translate("SS AEAD Node Use Type"))
for key, value in pairs(ss_aead_type) do for key, value in pairs(ss_aead_type) do
o:value(value, translate(value:gsub("^%l",string.upper))) o:value(value, translate(value:gsub("^%l",string.upper)))
end end
end end
if #trojan_type > 0 then if #trojan_type > 0 then
o = s:option(ListValue, "trojan_type", translate("Trojan Node Use Type")) o = s:option(ListValue, "trojan_type", translate("Trojan Node Use Type"))
for key, value in pairs(trojan_type) do for key, value in pairs(trojan_type) do
o:value(value, translate(value:gsub("^%l",string.upper))) o:value(value, translate(value:gsub("^%l",string.upper)))
end end
end end
---- Subscribe Delete All ---- Subscribe Delete All
o = s:option(Button, "_stop", translate("Delete All Subscribe Node")) o = s:option(Button, "_stop", translate("Delete All Subscribe Node"))
o.inputstyle = "remove" o.inputstyle = "remove"
function o.write(e, e) function o.write(e, e)
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua truncate > /dev/null 2>&1") luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua truncate > /dev/null 2>&1")
end end
o = s:option(Button, "_update", translate("Manual subscription All")) o = s:option(Button, "_update", translate("Manual subscription All"))
o.inputstyle = "apply" o.inputstyle = "apply"
function o.write(t, n) function o.write(t, n)
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start > /dev/null 2>&1 &") luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start > /dev/null 2>&1 &")
luci.http.redirect(api.url("log")) luci.http.redirect(api.url("log"))
end end
s = m:section(TypedSection, "subscribe_list", "", "<font color='red'>" .. translate("Please input the subscription url first, save and submit before manual subscription.") .. "</font>") s = m:section(TypedSection, "subscribe_list", "", "<font color='red'>" .. translate("Please input the subscription url first, save and submit before manual subscription.") .. "</font>")
@ -81,39 +81,39 @@ s.sortable = true
s.template = "cbi/tblsection" s.template = "cbi/tblsection"
s.extedit = api.url("node_subscribe_config", "%s") s.extedit = api.url("node_subscribe_config", "%s")
function s.create(e, t) function s.create(e, t)
local id = TypedSection.create(e, t) local id = TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(id)) luci.http.redirect(e.extedit:format(id))
end end
o = s:option(Value, "remark", translate("Remarks")) o = s:option(Value, "remark", translate("Remarks"))
o.width = "auto" o.width = "auto"
o.rmempty = false o.rmempty = false
o.validate = function(self, value, t) o.validate = function(self, value, t)
if value then if value then
local count = 0 local count = 0
m.uci:foreach(appname, "subscribe_list", function(e) m.uci:foreach(appname, "subscribe_list", function(e)
if e[".name"] ~= t and e["remark"] == value then if e[".name"] ~= t and e["remark"] == value then
count = count + 1 count = count + 1
end end
end) end)
if count > 0 then if count > 0 then
return nil, translate("This remark already exists, please change a new remark.") return nil, translate("This remark already exists, please change a new remark.")
end end
return value return value
end end
end end
o = s:option(DummyValue, "_node_count") o = s:option(DummyValue, "_node_count")
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
local remark = m:get(n, "remark") or "" local remark = m:get(n, "remark") or ""
local num = 0 local num = 0
m.uci:foreach(appname, "nodes", function(s) m.uci:foreach(appname, "nodes", function(s)
if s["add_from"] ~= "" and s["add_from"] == remark then if s["add_from"] ~= "" and s["add_from"] == remark then
num = num + 1 num = num + 1
end end
end) end)
return string.format("<span title='%s' style='color:red'>%s</span>", remark .. " " .. translate("Node num") .. ": " .. num, num) return string.format("<span title='%s' style='color:red'>%s</span>", remark .. " " .. translate("Node num") .. ": " .. num, num)
end end
o = s:option(Value, "url", translate("Subscribe URL")) o = s:option(Value, "url", translate("Subscribe URL"))
@ -123,15 +123,15 @@ o.rmempty = false
o = s:option(Button, "_remove", translate("Delete the subscribed node")) o = s:option(Button, "_remove", translate("Delete the subscribed node"))
o.inputstyle = "remove" o.inputstyle = "remove"
function o.write(t, n) function o.write(t, n)
local remark = m:get(n, "remark") or "" local remark = m:get(n, "remark") or ""
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua truncate " .. remark .. " > /dev/null 2>&1") luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua truncate " .. remark .. " > /dev/null 2>&1")
end end
o = s:option(Button, "_update", translate("Manual subscription")) o = s:option(Button, "_update", translate("Manual subscription"))
o.inputstyle = "apply" o.inputstyle = "apply"
function o.write(t, n) function o.write(t, n)
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start " .. n .. " > /dev/null 2>&1 &") luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start " .. n .. " > /dev/null 2>&1 &")
luci.http.redirect(api.url("log")) luci.http.redirect(api.url("log"))
end end
return m return m

View File

@ -10,24 +10,24 @@ local has_trojan_go = api.is_finded("trojan-go")
local ss_aead_type = {} local ss_aead_type = {}
local trojan_type = {} local trojan_type = {}
if has_ss then if has_ss then
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-libev" ss_aead_type[#ss_aead_type + 1] = "shadowsocks-libev"
end end
if has_ss_rust then if has_ss_rust then
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-rust" ss_aead_type[#ss_aead_type + 1] = "shadowsocks-rust"
end end
if has_trojan_plus then if has_trojan_plus then
trojan_type[#trojan_type + 1] = "trojan-plus" trojan_type[#trojan_type + 1] = "trojan-plus"
end end
if has_v2ray then if has_v2ray then
trojan_type[#trojan_type + 1] = "v2ray" trojan_type[#trojan_type + 1] = "v2ray"
ss_aead_type[#ss_aead_type + 1] = "v2ray" ss_aead_type[#ss_aead_type + 1] = "v2ray"
end end
if has_xray then if has_xray then
trojan_type[#trojan_type + 1] = "xray" trojan_type[#trojan_type + 1] = "xray"
ss_aead_type[#ss_aead_type + 1] = "xray" ss_aead_type[#ss_aead_type + 1] = "xray"
end end
if has_trojan_go then if has_trojan_go then
trojan_type[#trojan_type + 1] = "trojan-go" trojan_type[#trojan_type + 1] = "trojan-go"
end end
m = Map(appname) m = Map(appname)
@ -68,21 +68,21 @@ o:depends("filter_keyword_mode", "3")
o:depends("filter_keyword_mode", "4") o:depends("filter_keyword_mode", "4")
if #ss_aead_type > 0 then if #ss_aead_type > 0 then
o = s:option(ListValue, "ss_aead_type", translate("SS AEAD Node Use Type")) o = s:option(ListValue, "ss_aead_type", translate("SS AEAD Node Use Type"))
o.default = "global" o.default = "global"
o:value("global", translate("Use global config")) o:value("global", translate("Use global config"))
for key, value in pairs(ss_aead_type) do for key, value in pairs(ss_aead_type) do
o:value(value, translate(value:gsub("^%l",string.upper))) o:value(value, translate(value:gsub("^%l",string.upper)))
end end
end end
if #trojan_type > 0 then if #trojan_type > 0 then
o = s:option(ListValue, "trojan_type", translate("Trojan Node Use Type")) o = s:option(ListValue, "trojan_type", translate("Trojan Node Use Type"))
o.default = "global" o.default = "global"
o:value("global", translate("Use global config")) o:value("global", translate("Use global config"))
for key, value in pairs(trojan_type) do for key, value in pairs(trojan_type) do
o:value(value, translate(value:gsub("^%l",string.upper))) o:value(value, translate(value:gsub("^%l",string.upper)))
end end
end end
---- Enable auto update subscribe ---- Enable auto update subscribe

View File

@ -15,7 +15,7 @@ s.addremove = false
---- Delay Start ---- Delay Start
o = s:option(Value, "start_delay", translate("Delay Start"), o = s:option(Value, "start_delay", translate("Delay Start"),
translate("Units:seconds")) translate("Units:seconds"))
o.default = "1" o.default = "1"
o.rmempty = true o.rmempty = true
@ -54,7 +54,7 @@ for e = 0, 23 do o:value(e, e .. translate("oclock")) end
-- [[ Forwarding Settings ]]-- -- [[ Forwarding Settings ]]--
s = m:section(TypedSection, "global_forwarding", s = m:section(TypedSection, "global_forwarding",
translate("Forwarding Settings")) translate("Forwarding Settings"))
s.anonymous = true s.anonymous = true
s.addremove = false s.addremove = false
@ -66,9 +66,9 @@ o:value("1:65535", translate("All"))
---- UDP No Redir Ports ---- UDP No Redir Ports
o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"), o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"),
"<font color='red'>" .. translate( "<font color='red'>" .. translate(
"Fill in the ports you don't want to be forwarded by the agent, with the highest priority.") .. "Fill in the ports you don't want to be forwarded by the agent, with the highest priority.") ..
"</font>") "</font>")
o.default = "disable" o.default = "disable"
o:value("disable", translate("No patterns are used")) o:value("disable", translate("No patterns are used"))
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
@ -101,36 +101,36 @@ o:value("53", "DNS")
o = s:option(ListValue, "use_nft", translate("Firewall tools")) o = s:option(ListValue, "use_nft", translate("Firewall tools"))
o.default = "0" o.default = "0"
if has_fw3 then if has_fw3 then
o:value("0", "IPtables") o:value("0", "IPtables")
end end
if has_fw4 then if has_fw4 then
o:value("1", "NFtables") o:value("1", "NFtables")
end end
if (os.execute("lsmod | grep -i REDIRECT >/dev/null") == 0 and os.execute("lsmod | grep -i TPROXY >/dev/null") == 0) or (os.execute("lsmod | grep -i nft_redir >/dev/null") == 0 and os.execute("lsmod | grep -i nft_tproxy >/dev/null") == 0) then if (os.execute("lsmod | grep -i REDIRECT >/dev/null") == 0 and os.execute("lsmod | grep -i TPROXY >/dev/null") == 0) or (os.execute("lsmod | grep -i nft_redir >/dev/null") == 0 and os.execute("lsmod | grep -i nft_tproxy >/dev/null") == 0) then
o = s:option(ListValue, "tcp_proxy_way", translate("TCP Proxy Way")) o = s:option(ListValue, "tcp_proxy_way", translate("TCP Proxy Way"))
o.default = "tproxy" o.default = "redirect"
o:value("redirect", "REDIRECT") o:value("redirect", "REDIRECT")
o:value("tproxy", "TPROXY") o:value("tproxy", "TPROXY")
o:depends("ipv6_tproxy", false) o:depends("ipv6_tproxy", false)
o = s:option(ListValue, "_tcp_proxy_way", translate("TCP Proxy Way")) o = s:option(ListValue, "_tcp_proxy_way", translate("TCP Proxy Way"))
o.default = "tproxy" o.default = "tproxy"
o:value("tproxy", "TPROXY") o:value("tproxy", "TPROXY")
o:depends("ipv6_tproxy", true) o:depends("ipv6_tproxy", true)
o.write = function(self, section, value) o.write = function(self, section, value)
return self.map:set(section, "tcp_proxy_way", value) return self.map:set(section, "tcp_proxy_way", value)
end end
if os.execute("lsmod | grep -i ip6table_mangle >/dev/null") == 0 or os.execute("lsmod | grep -i nft_tproxy >/dev/null") == 0 then if os.execute("lsmod | grep -i ip6table_mangle >/dev/null") == 0 or os.execute("lsmod | grep -i nft_tproxy >/dev/null") == 0 then
---- IPv6 TProxy ---- IPv6 TProxy
o = s:option(Flag, "ipv6_tproxy", translate("IPv6 TProxy"), o = s:option(Flag, "ipv6_tproxy", translate("IPv6 TProxy"),
"<font color='red'>" .. translate( "<font color='red'>" .. translate(
"Experimental feature. Make sure that your node supports IPv6.") .. "Experimental feature. Make sure that your node supports IPv6.") ..
"</font>") "</font>")
o.default = 0 o.default = 0
o.rmempty = false o.rmempty = false
end end
end end
o = s:option(Flag, "accept_icmp", translate("Hijacking ICMP (PING)")) o = s:option(Flag, "accept_icmp", translate("Hijacking ICMP (PING)"))
@ -141,31 +141,31 @@ o:depends("ipv6_tproxy", true)
o.default = 0 o.default = 0
if has_v2ray or has_xray then if has_v2ray or has_xray then
o = s:option(Flag, "sniffing", translate("Sniffing (V2Ray/Xray)"), translate("When using the V2ray/Xray shunt, must be enabled, otherwise the shunt will invalid.")) o = s:option(Flag, "sniffing", translate("Sniffing (V2Ray/Xray)"), translate("When using the V2ray/Xray shunt, must be enabled, otherwise the shunt will invalid."))
o.default = 1 o.default = 1
o.rmempty = false o.rmempty = false
if has_xray then if has_xray then
route_only = s:option(Flag, "route_only", translate("Sniffing Route Only (Xray)"), translate("When enabled, the server not will resolve the domain name again.")) route_only = s:option(Flag, "route_only", translate("Sniffing Route Only (Xray)"), translate("When enabled, the server not will resolve the domain name again."))
route_only.default = 0 route_only.default = 0
route_only:depends("sniffing", true) route_only:depends("sniffing", true)
local domains_excluded = string.format("/usr/share/%s/rules/domains_excluded", appname) local domains_excluded = string.format("/usr/share/%s/rules/domains_excluded", appname)
o = s:option(TextValue, "no_sniffing_hosts", translate("No Sniffing Lists"), translate("Hosts added into No Sniffing Lists will not resolve again on server (Xray only).")) o = s:option(TextValue, "no_sniffing_hosts", translate("No Sniffing Lists"), translate("Hosts added into No Sniffing Lists will not resolve again on server (Xray only)."))
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) return fs.readfile(domains_excluded) or "" end o.cfgvalue = function(self, section) return fs.readfile(domains_excluded) or "" end
o.write = function(self, section, value) fs.writefile(domains_excluded, value:gsub("\r\n", "\n")) end o.write = function(self, section, value) fs.writefile(domains_excluded, value:gsub("\r\n", "\n")) end
o.remove = function(self, section, value) o.remove = function(self, section, value)
if route_only:formvalue(section) == "0" then if route_only:formvalue(section) == "0" then
fs.writefile(domains_excluded, "") fs.writefile(domains_excluded, "")
end end
end end
o:depends({sniffing = true, route_only = false}) o:depends({sniffing = true, route_only = false})
o = s:option(Value, "buffer_size", translate("Buffer Size (Xray)"), translate("Buffer size for every connection (kB)")) o = s:option(Value, "buffer_size", translate("Buffer Size (Xray)"), translate("Buffer size for every connection (kB)"))
o.rmempty = true o.rmempty = true
o.datatype = "uinteger" o.datatype = "uinteger"
end end
end end
return m return m

View File

@ -62,30 +62,30 @@ o.default = 0
o:depends("auto_update", true) o:depends("auto_update", true)
if has_v2ray or has_xray then if has_v2ray or has_xray then
o = s:option(Value, "v2ray_location_asset", translate("Location of V2ray/Xray asset"), translate("This variable specifies a directory where geoip.dat and geosite.dat files are.")) o = s:option(Value, "v2ray_location_asset", translate("Location of V2ray/Xray asset"), translate("This variable specifies a directory where geoip.dat and geosite.dat files are."))
o.default = "/usr/share/v2ray/" o.default = "/usr/share/v2ray/"
o.rmempty = false o.rmempty = false
s = m:section(TypedSection, "shunt_rules", "V2ray/Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>") s = m:section(TypedSection, "shunt_rules", "V2ray/Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>")
s.template = "cbi/tblsection" s.template = "cbi/tblsection"
s.anonymous = false s.anonymous = false
s.addremove = true s.addremove = true
s.sortable = true s.sortable = true
s.extedit = api.url("shunt_rules", "%s") s.extedit = api.url("shunt_rules", "%s")
function s.create(e, t) function s.create(e, t)
TypedSection.create(e, t) TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t)) luci.http.redirect(e.extedit:format(t))
end end
function s.remove(e, t) function s.remove(e, t)
m.uci:foreach(appname, "nodes", function(s) m.uci:foreach(appname, "nodes", function(s)
if s["protocol"] and s["protocol"] == "_shunt" then if s["protocol"] and s["protocol"] == "_shunt" then
m:del(s[".name"], t) m:del(s[".name"], t)
end end
end) end)
TypedSection.remove(e, t) TypedSection.remove(e, t)
end end
o = s:option(DummyValue, "remarks", translate("Remarks")) o = s:option(DummyValue, "remarks", translate("Remarks"))
end end
return m return m

View File

@ -24,28 +24,28 @@ o = s:taboption("direct_list", TextValue, "direct_host", "", "<font color='red'>
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(direct_host) or "" return fs.readfile(direct_host) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(direct_host, value:gsub("\r\n", "\n")) fs.writefile(direct_host, value:gsub("\r\n", "\n"))
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*") sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*")
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(direct_host, "") fs.writefile(direct_host, "")
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*") sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*")
end end
o.validate = function(self, value) o.validate = function(self, value)
local hosts= {} local hosts= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end)
for index, host in ipairs(hosts) do for index, host in ipairs(hosts) do
if host:find("#") and host:find("#") == 1 then if host:find("#") and host:find("#") == 1 then
return value return value
end end
if not datatypes.hostname(host) then if not datatypes.hostname(host) then
return nil, host .. " " .. translate("Not valid domain name, please re-enter!") return nil, host .. " " .. translate("Not valid domain name, please re-enter!")
end end
end end
return value return value
end end
---- Direct IP ---- Direct IP
@ -54,26 +54,26 @@ o = s:taboption("direct_list", TextValue, "direct_ip", "", "<font color='red'>"
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(direct_ip) or "" return fs.readfile(direct_ip) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(direct_ip, value:gsub("\r\n", "\n")) fs.writefile(direct_ip, value:gsub("\r\n", "\n"))
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(direct_ip, "") fs.writefile(direct_ip, "")
end end
o.validate = function(self, value) o.validate = function(self, value)
local ipmasks= {} local ipmasks= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
for index, ipmask in ipairs(ipmasks) do for index, ipmask in ipairs(ipmasks) do
if ipmask:find("#") and ipmask:find("#") == 1 then if ipmask:find("#") and ipmask:find("#") == 1 then
return value return value
end end
if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!") return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
end end
end end
return value return value
end end
---- Proxy Hosts ---- Proxy Hosts
@ -82,28 +82,28 @@ o = s:taboption("proxy_list", TextValue, "proxy_host", "", "<font color='red'>"
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(proxy_host) or "" return fs.readfile(proxy_host) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(proxy_host, value:gsub("\r\n", "\n")) fs.writefile(proxy_host, value:gsub("\r\n", "\n"))
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*") sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*")
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(proxy_host, "") fs.writefile(proxy_host, "")
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*") sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*")
end end
o.validate = function(self, value) o.validate = function(self, value)
local hosts= {} local hosts= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end)
for index, host in ipairs(hosts) do for index, host in ipairs(hosts) do
if host:find("#") and host:find("#") == 1 then if host:find("#") and host:find("#") == 1 then
return value return value
end end
if not datatypes.hostname(host) then if not datatypes.hostname(host) then
return nil, host .. " " .. translate("Not valid domain name, please re-enter!") return nil, host .. " " .. translate("Not valid domain name, please re-enter!")
end end
end end
return value return value
end end
---- Proxy IP ---- Proxy IP
@ -112,26 +112,26 @@ o = s:taboption("proxy_list", TextValue, "proxy_ip", "", "<font color='red'>" ..
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(proxy_ip) or "" return fs.readfile(proxy_ip) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(proxy_ip, value:gsub("\r\n", "\n")) fs.writefile(proxy_ip, value:gsub("\r\n", "\n"))
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(proxy_ip, "") fs.writefile(proxy_ip, "")
end end
o.validate = function(self, value) o.validate = function(self, value)
local ipmasks= {} local ipmasks= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
for index, ipmask in ipairs(ipmasks) do for index, ipmask in ipairs(ipmasks) do
if ipmask:find("#") and ipmask:find("#") == 1 then if ipmask:find("#") and ipmask:find("#") == 1 then
return value return value
end end
if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!") return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
end end
end end
return value return value
end end
---- Block Hosts ---- Block Hosts
@ -140,26 +140,26 @@ o = s:taboption("block_list", TextValue, "block_host", "", "<font color='red'>"
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(block_host) or "" return fs.readfile(block_host) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(block_host, value:gsub("\r\n", "\n")) fs.writefile(block_host, value:gsub("\r\n", "\n"))
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(block_host, "") fs.writefile(block_host, "")
end end
o.validate = function(self, value) o.validate = function(self, value)
local hosts= {} local hosts= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end)
for index, host in ipairs(hosts) do for index, host in ipairs(hosts) do
if host:find("#") and host:find("#") == 1 then if host:find("#") and host:find("#") == 1 then
return value return value
end end
if not datatypes.hostname(host) then if not datatypes.hostname(host) then
return nil, host .. " " .. translate("Not valid domain name, please re-enter!") return nil, host .. " " .. translate("Not valid domain name, please re-enter!")
end end
end end
return value return value
end end
---- Block IP ---- Block IP
@ -168,26 +168,26 @@ o = s:taboption("block_list", TextValue, "block_ip", "", "<font color='red'>" ..
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(block_ip) or "" return fs.readfile(block_ip) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(block_ip, value:gsub("\r\n", "\n")) fs.writefile(block_ip, value:gsub("\r\n", "\n"))
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(block_ip, "") fs.writefile(block_ip, "")
end end
o.validate = function(self, value) o.validate = function(self, value)
local ipmasks= {} local ipmasks= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
for index, ipmask in ipairs(ipmasks) do for index, ipmask in ipairs(ipmasks) do
if ipmask:find("#") and ipmask:find("#") == 1 then if ipmask:find("#") and ipmask:find("#") == 1 then
return value return value
end end
if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!") return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
end end
end end
return value return value
end end
---- Lan IPv4 ---- Lan IPv4
@ -196,26 +196,26 @@ o = s:taboption("lan_ip_list", TextValue, "lanlist_ipv4", "", "<font color='red'
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(lanlist_ipv4) or "" return fs.readfile(lanlist_ipv4) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(lanlist_ipv4, value:gsub("\r\n", "\n")) fs.writefile(lanlist_ipv4, value:gsub("\r\n", "\n"))
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(lanlist_ipv4, "") fs.writefile(lanlist_ipv4, "")
end end
o.validate = function(self, value) o.validate = function(self, value)
local ipmasks= {} local ipmasks= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
for index, ipmask in ipairs(ipmasks) do for index, ipmask in ipairs(ipmasks) do
if ipmask:find("#") and ipmask:find("#") == 1 then if ipmask:find("#") and ipmask:find("#") == 1 then
return value return value
end end
if not datatypes.ipmask4(ipmask) then if not datatypes.ipmask4(ipmask) then
return nil, ipmask .. " " .. translate("Not valid IPv4 format, please re-enter!") return nil, ipmask .. " " .. translate("Not valid IPv4 format, please re-enter!")
end end
end end
return value return value
end end
---- Lan IPv6 ---- Lan IPv6
@ -224,26 +224,26 @@ o = s:taboption("lan_ip_list", TextValue, "lanlist_ipv6", "", "<font color='red'
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(lanlist_ipv6) or "" return fs.readfile(lanlist_ipv6) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(lanlist_ipv6, value:gsub("\r\n", "\n")) fs.writefile(lanlist_ipv6, value:gsub("\r\n", "\n"))
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(lanlist_ipv6, "") fs.writefile(lanlist_ipv6, "")
end end
o.validate = function(self, value) o.validate = function(self, value)
local ipmasks= {} local ipmasks= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
for index, ipmask in ipairs(ipmasks) do for index, ipmask in ipairs(ipmasks) do
if ipmask:find("#") and ipmask:find("#") == 1 then if ipmask:find("#") and ipmask:find("#") == 1 then
return value return value
end end
if not datatypes.ipmask6(ipmask) then if not datatypes.ipmask6(ipmask) then
return nil, ipmask .. " " .. translate("Not valid IPv6 format, please re-enter!") return nil, ipmask .. " " .. translate("Not valid IPv6 format, please re-enter!")
end end
end end
return value return value
end end
---- Route Hosts ---- Route Hosts
@ -252,13 +252,13 @@ o = s:taboption("route_hosts", TextValue, "hosts", "", "<font color='red'>" .. t
o.rows = 15 o.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return fs.readfile(hosts) or "" return fs.readfile(hosts) or ""
end end
o.write = function(self, section, value) o.write = function(self, section, value)
fs.writefile(hosts, value:gsub("\r\n", "\n")) fs.writefile(hosts, value:gsub("\r\n", "\n"))
end end
o.remove = function(self, section, value) o.remove = function(self, section, value)
fs.writefile(hosts, "") fs.writefile(hosts, "")
end end
return m return m

View File

@ -22,29 +22,29 @@ domain_list = s:option(TextValue, "domain_list", translate("Domain"))
domain_list.rows = 10 domain_list.rows = 10
domain_list.wrap = "off" domain_list.wrap = "off"
domain_list.validate = function(self, value) domain_list.validate = function(self, value)
local hosts= {} local hosts= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end)
for index, host in ipairs(hosts) do for index, host in ipairs(hosts) do
local flag = 1 local flag = 1
local tmp_host = host local tmp_host = host
if host:find("regexp:") and host:find("regexp:") == 1 then if host:find("regexp:") and host:find("regexp:") == 1 then
flag = 0 flag = 0
elseif host:find("domain:.") and host:find("domain:.") == 1 then elseif host:find("domain:.") and host:find("domain:.") == 1 then
tmp_host = host:gsub("domain:", "") tmp_host = host:gsub("domain:", "")
elseif host:find("full:.") and host:find("full:.") == 1 then elseif host:find("full:.") and host:find("full:.") == 1 then
tmp_host = host:gsub("full:", "") tmp_host = host:gsub("full:", "")
elseif host:find("geosite:") and host:find("geosite:") == 1 then elseif host:find("geosite:") and host:find("geosite:") == 1 then
flag = 0 flag = 0
elseif host:find("ext:") and host:find("ext:") == 1 then elseif host:find("ext:") and host:find("ext:") == 1 then
flag = 0 flag = 0
end end
if flag == 1 then if flag == 1 then
if not datatypes.hostname(tmp_host) then if not datatypes.hostname(tmp_host) then
return nil, tmp_host .. " " .. translate("Not valid domain name, please re-enter!") return nil, tmp_host .. " " .. translate("Not valid domain name, please re-enter!")
end end
end end
end end
return value return value
end end
domain_list.description = "<br /><ul><li>" .. translate("Plaintext: If this string matches any part of the targeting domain, this rule takes effet. Example: rule 'sina.com' matches targeting domain 'sina.com', 'sina.com.cn' and 'www.sina.com', but not 'sina.cn'.") domain_list.description = "<br /><ul><li>" .. translate("Plaintext: If this string matches any part of the targeting domain, this rule takes effet. Example: rule 'sina.com' matches targeting domain 'sina.com', 'sina.com.cn' and 'www.sina.com', but not 'sina.cn'.")
.. "</li><li>" .. translate("Regular expression: Begining with 'regexp:', the rest is a regular expression. When the regexp matches targeting domain, this rule takes effect. Example: rule 'regexp:\\.goo.*\\.com$' matches 'www.google.com' and 'fonts.googleapis.com', but not 'google.com'.") .. "</li><li>" .. translate("Regular expression: Begining with 'regexp:', the rest is a regular expression. When the regexp matches targeting domain, this rule takes effect. Example: rule 'regexp:\\.goo.*\\.com$' matches 'www.google.com' and 'fonts.googleapis.com', but not 'google.com'.")
@ -57,18 +57,18 @@ ip_list = s:option(TextValue, "ip_list", "IP")
ip_list.rows = 10 ip_list.rows = 10
ip_list.wrap = "off" ip_list.wrap = "off"
ip_list.validate = function(self, value) ip_list.validate = function(self, value)
local ipmasks= {} local ipmasks= {}
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end) string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
for index, ipmask in ipairs(ipmasks) do for index, ipmask in ipairs(ipmasks) do
if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 then if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 then
elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 then elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 then
else else
if not (datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask)) then if not (datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask)) then
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!") return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
end end
end end
end end
return value return value
end end
ip_list.description = "<br /><ul><li>" .. translate("IP: such as '127.0.0.1'.") ip_list.description = "<br /><ul><li>" .. translate("IP: such as '127.0.0.1'.")
.. "</li><li>" .. translate("CIDR: such as '127.0.0.0/8'.") .. "</li><li>" .. translate("CIDR: such as '127.0.0.0/8'.")

View File

@ -16,15 +16,15 @@ t.sortable = true
t.template = "cbi/tblsection" t.template = "cbi/tblsection"
t.extedit = api.url("server_user", "%s") t.extedit = api.url("server_user", "%s")
function t.create(e, t) function t.create(e, t)
local uuid = api.gen_uuid() local uuid = api.gen_uuid()
t = uuid t = uuid
TypedSection.create(e, t) TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t)) luci.http.redirect(e.extedit:format(t))
end end
function t.remove(e, t) function t.remove(e, t)
e.map.proceed = true e.map.proceed = true
e.map:del(t) e.map:del(t)
luci.http.redirect(api.url("server")) luci.http.redirect(api.url("server"))
end end
e = t:option(Flag, "enable", translate("Enable")) e = t:option(Flag, "enable", translate("Enable"))
@ -34,7 +34,7 @@ e.rmempty = false
e = t:option(DummyValue, "status", translate("Status")) e = t:option(DummyValue, "status", translate("Status"))
e.rawhtml = true e.rawhtml = true
e.cfgvalue = function(t, n) e.cfgvalue = function(t, n)
return string.format('<font class="_users_status">%s</font>', translate("Collecting data...")) return string.format('<font class="_users_status">%s</font>', translate("Collecting data..."))
end end
e = t:option(DummyValue, "remarks", translate("Remarks")) e = t:option(DummyValue, "remarks", translate("Remarks"))
@ -43,21 +43,21 @@ e.width = "15%"
---- Type ---- Type
e = t:option(DummyValue, "type", translate("Type")) e = t:option(DummyValue, "type", translate("Type"))
e.cfgvalue = function(t, n) e.cfgvalue = function(t, n)
local v = Value.cfgvalue(t, n) local v = Value.cfgvalue(t, n)
if v then if v then
if v == "V2ray" or v == "Xray" then if v == "V2ray" or v == "Xray" then
local protocol = m:get(n, "protocol") local protocol = m:get(n, "protocol")
if protocol == "vmess" then if protocol == "vmess" then
protocol = "VMess" protocol = "VMess"
elseif protocol == "vless" then elseif protocol == "vless" then
protocol = "VLESS" protocol = "VLESS"
else else
protocol = protocol:gsub("^%l",string.upper) protocol = protocol:gsub("^%l",string.upper)
end end
return v .. " -> " .. protocol return v .. " -> " .. protocol
end end
return v return v
end end
end end
e = t:option(DummyValue, "port", translate("Port")) e = t:option(DummyValue, "port", translate("Port"))
@ -70,4 +70,3 @@ m:append(Template("passwall/server/log"))
m:append(Template("passwall/server/users_list_status")) m:append(Template("passwall/server/users_list_status"))
return m return m

View File

@ -1,49 +1,49 @@
local api = require "luci.passwall.api" local api = require "luci.passwall.api"
local ss_encrypt_method_list = { local ss_encrypt_method_list = {
"rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr",
"aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb", "aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb",
"camellia-192-cfb", "camellia-256-cfb", "salsa20", "chacha20", "camellia-192-cfb", "camellia-256-cfb", "salsa20", "chacha20",
"chacha20-ietf", -- aead "chacha20-ietf", -- aead
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305" "xchacha20-ietf-poly1305"
} }
local ss_rust_encrypt_method_list = { local ss_rust_encrypt_method_list = {
"plain", "none", "plain", "none",
"aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
} }
local ssr_encrypt_method_list = { local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb", "none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
"aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
"cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20", "cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20",
"chacha20-ietf" "chacha20-ietf"
} }
local ssr_protocol_list = { local ssr_protocol_list = {
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple", "origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5", "auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
"auth_chain_d", "auth_chain_e", "auth_chain_f" "auth_chain_d", "auth_chain_e", "auth_chain_f"
} }
local ssr_obfs_list = { local ssr_obfs_list = {
"plain", "http_simple", "http_post", "random_head", "tls_simple", "plain", "http_simple", "http_post", "random_head", "tls_simple",
"tls1.0_session_auth", "tls1.2_ticket_auth" "tls1.0_session_auth", "tls1.2_ticket_auth"
} }
local v_ss_encrypt_method_list = { local v_ss_encrypt_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305" "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305"
} }
local x_ss_encrypt_method_list = { local x_ss_encrypt_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
} }
local header_type_list = { local header_type_list = {
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard" "none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
} }
local encrypt_methods_ss_aead = { local encrypt_methods_ss_aead = {
@ -69,39 +69,39 @@ remarks.rmempty = false
type = s:option(ListValue, "type", translate("Type")) type = s:option(ListValue, "type", translate("Type"))
if api.is_finded("microsocks") then if api.is_finded("microsocks") then
type:value("Socks", translate("Socks")) type:value("Socks", translate("Socks"))
end end
if api.is_finded("ss-server") then if api.is_finded("ss-server") then
type:value("SS", translate("Shadowsocks")) type:value("SS", translate("Shadowsocks"))
end end
if api.is_finded("ssserver") then if api.is_finded("ssserver") then
type:value("SS-Rust", translate("Shadowsocks Rust")) type:value("SS-Rust", translate("Shadowsocks Rust"))
end end
if api.is_finded("ssr-server") then if api.is_finded("ssr-server") then
type:value("SSR", translate("ShadowsocksR")) type:value("SSR", translate("ShadowsocksR"))
end end
if api.is_finded("v2ray") then if api.is_finded("v2ray") then
type:value("V2ray", translate("V2ray")) type:value("V2ray", translate("V2ray"))
end end
if api.is_finded("xray") then if api.is_finded("xray") then
type:value("Xray", translate("Xray")) type:value("Xray", translate("Xray"))
end end
if api.is_finded("brook") then if api.is_finded("brook") then
type:value("Brook", translate("Brook")) type:value("Brook", translate("Brook"))
end end
--[[ --[[
if api.is_finded("trojan-plus") or api.is_finded("trojan") then if api.is_finded("trojan-plus") or api.is_finded("trojan") then
type:value("Trojan", translate("Trojan")) type:value("Trojan", translate("Trojan"))
end end
]]-- ]]--
if api.is_finded("trojan-plus") then if api.is_finded("trojan-plus") then
type:value("Trojan-Plus", translate("Trojan-Plus")) type:value("Trojan-Plus", translate("Trojan-Plus"))
end end
if api.is_finded("trojan-go") then if api.is_finded("trojan-go") then
type:value("Trojan-Go", translate("Trojan-Go")) type:value("Trojan-Go", translate("Trojan-Go"))
end end
if api.is_finded("hysteria") then if api.is_finded("hysteria") then
type:value("Hysteria", translate("Hysteria")) type:value("Hysteria", translate("Hysteria"))
end end
protocol = s:option(ListValue, "protocol", translate("Protocol")) protocol = s:option(ListValue, "protocol", translate("Protocol"))
@ -137,14 +137,14 @@ port.rmempty = false
auth = s:option(Flag, "auth", translate("Auth")) auth = s:option(Flag, "auth", translate("Auth"))
auth.validate = function(self, value, t) auth.validate = function(self, value, t)
if value and value == "1" then if value and value == "1" then
local user_v = username:formvalue(t) or "" local user_v = username:formvalue(t) or ""
local pass_v = password:formvalue(t) or "" local pass_v = password:formvalue(t) or ""
if user_v == "" or pass_v == "" then if user_v == "" or pass_v == "" then
return nil, translate("Username and Password must be used together!") return nil, translate("Username and Password must be used together!")
end end
end end
return value return value
end end
auth:depends("type", "Socks") auth:depends("type", "Socks")
auth:depends({ type = "V2ray", protocol = "socks" }) auth:depends({ type = "V2ray", protocol = "socks" })
@ -343,7 +343,7 @@ udp_forward:depends({ type = "Xray", protocol = "socks" })
uuid = s:option(DynamicList, "uuid", translate("ID") .. "/" .. translate("Password")) uuid = s:option(DynamicList, "uuid", translate("ID") .. "/" .. translate("Password"))
for i = 1, 3 do for i = 1, 3 do
uuid:value(api.gen_uuid(1)) uuid:value(api.gen_uuid(1))
end end
uuid:depends({ type = "V2ray", protocol = "vmess" }) uuid:depends({ type = "V2ray", protocol = "vmess" })
uuid:depends({ type = "V2ray", protocol = "vless" }) uuid:depends({ type = "V2ray", protocol = "vless" })
@ -358,20 +358,20 @@ uuid:depends("type", "Trojan-Plus")
tls = s:option(Flag, "tls", translate("TLS")) tls = s:option(Flag, "tls", translate("TLS"))
tls.default = 0 tls.default = 0
tls.validate = function(self, value, t) tls.validate = function(self, value, t)
if value then if value then
local type = type:formvalue(t) or "" local type = type:formvalue(t) or ""
if value == "0" and (type == "Trojan" or type == "Trojan-Plus") then if value == "0" and (type == "Trojan" or type == "Trojan-Plus") then
return nil, translate("Original Trojan only supported 'tls', please choose 'tls'.") return nil, translate("Original Trojan only supported 'tls', please choose 'tls'.")
end end
if value == "1" then if value == "1" then
local ca = tls_certificateFile:formvalue(t) or "" local ca = tls_certificateFile:formvalue(t) or ""
local key = tls_keyFile:formvalue(t) or "" local key = tls_keyFile:formvalue(t) or ""
if ca == "" or key == "" then if ca == "" or key == "" then
return nil, translate("Public key and Private key path can not be empty!") return nil, translate("Public key and Private key path can not be empty!")
end end
end end
return value return value
end end
end end
tls:depends({ type = "V2ray", protocol = "vmess" }) tls:depends({ type = "V2ray", protocol = "vmess" })
tls:depends({ type = "V2ray", protocol = "vless" }) tls:depends({ type = "V2ray", protocol = "vless" })
@ -411,14 +411,14 @@ alpn:depends({ type = "Xray", tls = true })
tls_certificateFile = s:option(FileUpload, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") tls_certificateFile = s:option(FileUpload, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
tls_certificateFile.validate = function(self, value, t) tls_certificateFile.validate = function(self, value, t)
if value and value ~= "" then if value and value ~= "" then
if not nixio.fs.access(value) then if not nixio.fs.access(value) then
return nil, translate("Can't find this file!") return nil, translate("Can't find this file!")
else else
return value return value
end end
end end
return nil return nil
end end
tls_certificateFile.default = "/etc/config/ssl/" .. arg[1] .. ".pem" tls_certificateFile.default = "/etc/config/ssl/" .. arg[1] .. ".pem"
tls_certificateFile:depends("tls", true) tls_certificateFile:depends("tls", true)
@ -426,14 +426,14 @@ tls_certificateFile:depends("type", "Hysteria")
tls_keyFile = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key") tls_keyFile = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
tls_keyFile.validate = function(self, value, t) tls_keyFile.validate = function(self, value, t)
if value and value ~= "" then if value and value ~= "" then
if not nixio.fs.access(value) then if not nixio.fs.access(value) then
return nil, translate("Can't find this file!") return nil, translate("Can't find this file!")
else else
return value return value
end end
end end
return nil return nil
end end
tls_keyFile.default = "/etc/config/ssl/" .. arg[1] .. ".key" tls_keyFile.default = "/etc/config/ssl/" .. arg[1] .. ".key"
tls_keyFile:depends("tls", true) tls_keyFile:depends("tls", true)
@ -673,12 +673,12 @@ accept_lan:depends("type", "Xray")
local nodes_table = {} local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do for k, e in ipairs(api.get_valid_nodes()) do
if e.node_type == "normal" and (e.type == "V2ray" or e.type == "Xray") then if e.node_type == "normal" and (e.type == "V2ray" or e.type == "Xray") then
nodes_table[#nodes_table + 1] = { nodes_table[#nodes_table + 1] = {
id = e[".name"], id = e[".name"],
remarks = e["remark"] remarks = e["remark"]
} }
end end
end end
outbound_node = s:option(ListValue, "outbound_node", translate("outbound node")) outbound_node = s:option(ListValue, "outbound_node", translate("outbound node"))

File diff suppressed because it is too large Load Diff

View File

@ -1,99 +1,99 @@
local _M = {} local _M = {}
local function gh_release_url(self) local function gh_release_url(self)
return "https://api.github.com/repos/" .. self.repo .. "/releases/latest" return "https://api.github.com/repos/" .. self.repo .. "/releases/latest"
end end
local function gh_pre_release_url(self) local function gh_pre_release_url(self)
return "https://api.github.com/repos/" .. self.repo .. "/releases?per_page=1" return "https://api.github.com/repos/" .. self.repo .. "/releases?per_page=1"
end end
_M.brook = { _M.brook = {
name = "Brook", name = "Brook",
repo = "txthinking/brook", repo = "txthinking/brook",
get_url = gh_release_url, get_url = gh_release_url,
cmd_version = "-v | awk '{print $3}'", cmd_version = "-v | awk '{print $3}'",
zipped = false, zipped = false,
default_path = "/usr/bin/brook", default_path = "/usr/bin/brook",
match_fmt_str = "linux_%s$", match_fmt_str = "linux_%s$",
file_tree = {} file_tree = {}
} }
_M.hysteria = { _M.hysteria = {
name = "Hysteria", name = "Hysteria",
repo = "HyNetwork/hysteria", repo = "HyNetwork/hysteria",
get_url = gh_release_url, get_url = gh_release_url,
cmd_version = "-v | awk '{print $3}'", cmd_version = "-v | awk '{print $3}'",
zipped = false, zipped = false,
default_path = "/usr/bin/hysteria", default_path = "/usr/bin/hysteria",
match_fmt_str = "linux%%-%s$", match_fmt_str = "linux%%-%s$",
file_tree = { file_tree = {
armv6 = "arm", armv6 = "arm",
armv7 = "arm" armv7 = "arm"
} }
} }
_M["trojan-go"] = { _M["trojan-go"] = {
name = "Trojan-Go", name = "Trojan-Go",
repo = "p4gefau1t/trojan-go", repo = "p4gefau1t/trojan-go",
get_url = gh_release_url, get_url = gh_release_url,
cmd_version = "-version | awk '{print $2}' | sed -n 1P", cmd_version = "-version | awk '{print $2}' | sed -n 1P",
zipped = true, zipped = true,
default_path = "/usr/bin/trojan-go", default_path = "/usr/bin/trojan-go",
match_fmt_str = "linux%%-%s%%.zip", match_fmt_str = "linux%%-%s%%.zip",
file_tree = { file_tree = {
aarch64 = "armv8", aarch64 = "armv8",
armv8 = "armv8", armv8 = "armv8",
mips = "mips%-hardfloat", mips = "mips%-hardfloat",
mipsel = "mipsle%-hardfloat" mipsel = "mipsle%-hardfloat"
} }
} }
_M.v2ray = { _M.v2ray = {
name = "V2ray", name = "V2ray",
repo = "v2fly/v2ray-core", repo = "v2fly/v2ray-core",
get_url = gh_pre_release_url, get_url = gh_pre_release_url,
cmd_version = "version | awk '{print $2}' | sed -n 1P", cmd_version = "version | awk '{print $2}' | sed -n 1P",
zipped = true, zipped = true,
default_path = "/usr/bin/v2ray", default_path = "/usr/bin/v2ray",
match_fmt_str = "linux%%-%s", match_fmt_str = "linux%%-%s",
file_tree = { file_tree = {
x86_64 = "64", x86_64 = "64",
x86 = "32", x86 = "32",
mips = "mips32", mips = "mips32",
mipsel = "mips32le" mipsel = "mips32le"
} }
} }
_M.xray = { _M.xray = {
name = "Xray", name = "Xray",
repo = "XTLS/Xray-core", repo = "XTLS/Xray-core",
get_url = gh_pre_release_url, get_url = gh_pre_release_url,
cmd_version = _M.v2ray.cmd_version, cmd_version = _M.v2ray.cmd_version,
zipped = true, zipped = true,
default_path = "/usr/bin/xray", default_path = "/usr/bin/xray",
match_fmt_str = _M.v2ray.match_fmt_str, match_fmt_str = _M.v2ray.match_fmt_str,
file_tree = _M.v2ray.file_tree file_tree = _M.v2ray.file_tree
} }
_M["chinadns-ng"] = { _M["chinadns-ng"] = {
name = "ChinaDNS-NG", name = "ChinaDNS-NG",
repo = "zfl9/chinadns-ng", repo = "zfl9/chinadns-ng",
get_url = gh_pre_release_url, get_url = gh_pre_release_url,
cmd_version = "-V | awk '{print $2}'", cmd_version = "-V | awk '{print $2}'",
zipped = false, zipped = false,
default_path = "/usr/bin/chinadns-ng", default_path = "/usr/bin/chinadns-ng",
match_fmt_str = "%s$", match_fmt_str = "%s$",
file_tree = { file_tree = {
x86_64 = "x86_64", x86_64 = "x86_64",
x86 = "i686", x86 = "i686",
mipsel = "mipsel", mipsel = "mipsel",
aarch64 = "aarch64", aarch64 = "aarch64",
armv5 = "arm%-eabi", armv5 = "arm%-eabi",
armv6 = "armv6%-eabihf", armv6 = "armv6%-eabihf",
armv7 = "armv7l%-eabihf", armv7 = "armv7l%-eabihf",
armv8 = "aarch64" armv8 = "aarch64"
} }
} }
return _M return _M

View File

@ -18,215 +18,215 @@ local ip6t_bin = sys.exec("echo -n $(/usr/share/passwall/iptables.sh get_ip6t_bi
local nft_flag = api.is_finded("fw4") and "1" or "0" local nft_flag = api.is_finded("fw4") and "1" or "0"
local function log(...) local function log(...)
local f, err = io.open(LOG_APP_FILE, "a") local f, err = io.open(LOG_APP_FILE, "a")
if f and err == nil then if f and err == nil then
local str = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ") local str = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
f:write(str .. "\n") f:write(str .. "\n")
f:close() f:close()
end end
end end
local function cmd(cmd) local function cmd(cmd)
sys.call(cmd) sys.call(cmd)
end end
local function ipt(arg) local function ipt(arg)
cmd(ipt_bin .. " -w " .. arg) cmd(ipt_bin .. " -w " .. arg)
end end
local function ip6t(arg) local function ip6t(arg)
cmd(ip6t_bin .. " -w " .. arg) cmd(ip6t_bin .. " -w " .. arg)
end end
local function ln_run(s, d, command, output) local function ln_run(s, d, command, output)
if not output then if not output then
output = "/dev/null" output = "/dev/null"
end end
d = TMP_BIN_PATH .. "/" .. d d = TMP_BIN_PATH .. "/" .. d
cmd(string.format('[ ! -f "%s" ] && ln -s %s %s 2>/dev/null', d, s, d)) cmd(string.format('[ ! -f "%s" ] && ln -s %s %s 2>/dev/null', d, s, d))
return string.format("%s >%s 2>&1 &", d .. " " ..command, output) return string.format("%s >%s 2>&1 &", d .. " " ..command, output)
end end
local function gen_include() local function gen_include()
cmd(string.format("echo '#!/bin/sh' > /tmp/etc/%s.include", CONFIG)) cmd(string.format("echo '#!/bin/sh' > /tmp/etc/%s.include", CONFIG))
if nft_flag == "1" then if nft_flag == "1" then
cmd("echo \"\" > " .. CONFIG_PATH .. "/" .. CONFIG .. ".nft") cmd("echo \"\" > " .. CONFIG_PATH .. "/" .. CONFIG .. ".nft")
local nft_cmd="for chain in $(nft -a list chains |grep -E \"chain PSW-SERVER\" |awk -F ' ' '{print$2}'); do\n nft list chain inet fw4 ${chain} >> " .. CONFIG_PATH .. "/" .. CONFIG .. ".nft\n done" local nft_cmd="for chain in $(nft -a list chains |grep -E \"chain PSW-SERVER\" |awk -F ' ' '{print$2}'); do\n nft list chain inet fw4 ${chain} >> " .. CONFIG_PATH .. "/" .. CONFIG .. ".nft\n done"
cmd(nft_cmd) cmd(nft_cmd)
end end
local function extract_rules(n, a) local function extract_rules(n, a)
local _ipt = ipt_bin local _ipt = ipt_bin
if n == "6" then if n == "6" then
_ipt = ip6t_bin _ipt = ip6t_bin
end end
local result = "*" .. a local result = "*" .. a
result = result .. "\n" .. sys.exec(_ipt .. '-save -t ' .. a .. ' | grep "PSW-SERVER" | sed -e "s/^-A \\(INPUT\\)/-I \\1 1/"') result = result .. "\n" .. sys.exec(_ipt .. '-save -t ' .. a .. ' | grep "PSW-SERVER" | sed -e "s/^-A \\(INPUT\\)/-I \\1 1/"')
result = result .. "COMMIT" result = result .. "COMMIT"
return result return result
end end
local f, err = io.open("/tmp/etc/" .. CONFIG .. ".include", "a") local f, err = io.open("/tmp/etc/" .. CONFIG .. ".include", "a")
if f and err == nil then if f and err == nil then
if nft_flag == "0" then if nft_flag == "0" then
f:write(ipt_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ipt_bin .. '-restore -c' .. "\n") f:write(ipt_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ipt_bin .. '-restore -c' .. "\n")
f:write(ipt_bin .. '-restore -n <<-EOT' .. "\n") f:write(ipt_bin .. '-restore -n <<-EOT' .. "\n")
f:write(extract_rules("4", "filter") .. "\n") f:write(extract_rules("4", "filter") .. "\n")
f:write("EOT" .. "\n") f:write("EOT" .. "\n")
f:write(ip6t_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ip6t_bin .. '-restore -c' .. "\n") f:write(ip6t_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ip6t_bin .. '-restore -c' .. "\n")
f:write(ip6t_bin .. '-restore -n <<-EOT' .. "\n") f:write(ip6t_bin .. '-restore -n <<-EOT' .. "\n")
f:write(extract_rules("6", "filter") .. "\n") f:write(extract_rules("6", "filter") .. "\n")
f:write("EOT" .. "\n") f:write("EOT" .. "\n")
f:close() f:close()
else else
f:write("nft -f " .. CONFIG_PATH .. "/" .. CONFIG .. ".nft\n") f:write("nft -f " .. CONFIG_PATH .. "/" .. CONFIG .. ".nft\n")
f:write("nft insert rule inet fw4 input position 0 counter jump PSW-SERVER") f:write("nft insert rule inet fw4 input position 0 counter jump PSW-SERVER")
f:close() f:close()
end end
end end
end end
local function start() local function start()
local enabled = tonumber(uci:get(CONFIG, "@global[0]", "enable") or 0) local enabled = tonumber(uci:get(CONFIG, "@global[0]", "enable") or 0)
if enabled == nil or enabled == 0 then if enabled == nil or enabled == 0 then
return return
end end
cmd(string.format("mkdir -p %s %s", CONFIG_PATH, TMP_BIN_PATH)) cmd(string.format("mkdir -p %s %s", CONFIG_PATH, TMP_BIN_PATH))
cmd(string.format("touch %s", LOG_APP_FILE)) cmd(string.format("touch %s", LOG_APP_FILE))
if nft_flag == "0" then if nft_flag == "0" then
ipt("-N PSW-SERVER") ipt("-N PSW-SERVER")
ipt("-I INPUT -j PSW-SERVER") ipt("-I INPUT -j PSW-SERVER")
ip6t("-N PSW-SERVER") ip6t("-N PSW-SERVER")
ip6t("-I INPUT -j PSW-SERVER") ip6t("-I INPUT -j PSW-SERVER")
else else
cmd("nft add chain inet fw4 PSW-SERVER\n") cmd("nft add chain inet fw4 PSW-SERVER\n")
cmd("nft insert rule inet fw4 input position 0 counter jump PSW-SERVER") cmd("nft insert rule inet fw4 input position 0 counter jump PSW-SERVER")
end end
uci:foreach(CONFIG, "user", function(user) uci:foreach(CONFIG, "user", function(user)
local id = user[".name"] local id = user[".name"]
local enable = user.enable local enable = user.enable
if enable and tonumber(enable) == 1 then if enable and tonumber(enable) == 1 then
local enable_log = user.log local enable_log = user.log
local log_path = nil local log_path = nil
if enable_log and enable_log == "1" then if enable_log and enable_log == "1" then
log_path = CONFIG_PATH .. "/" .. id .. ".log" log_path = CONFIG_PATH .. "/" .. id .. ".log"
else else
log_path = nil log_path = nil
end end
local remarks = user.remarks local remarks = user.remarks
local port = tonumber(user.port) local port = tonumber(user.port)
local bin local bin
local config = {} local config = {}
local config_file = CONFIG_PATH .. "/" .. id .. ".json" local config_file = CONFIG_PATH .. "/" .. id .. ".json"
local udp_forward = 1 local udp_forward = 1
local type = user.type or "" local type = user.type or ""
if type == "Socks" then if type == "Socks" then
local auth = "" local auth = ""
if user.auth and user.auth == "1" then if user.auth and user.auth == "1" then
local username = user.username or "" local username = user.username or ""
local password = user.password or "" local password = user.password or ""
if username ~= "" and password ~= "" then if username ~= "" and password ~= "" then
username = "-u " .. username username = "-u " .. username
password = "-P " .. password password = "-P " .. password
auth = username .. " " .. password auth = username .. " " .. password
end end
end end
bin = ln_run("/usr/bin/microsocks", "microsocks_" .. id, string.format("-i :: -p %s %s", port, auth), log_path) bin = ln_run("/usr/bin/microsocks", "microsocks_" .. id, string.format("-i :: -p %s %s", port, auth), log_path)
elseif type == "SS" or type == "SSR" then elseif type == "SS" or type == "SSR" then
config = require(require_dir .. "util_shadowsocks").gen_config_server(user) config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
local udp_param = "" local udp_param = ""
udp_forward = tonumber(user.udp_forward) or 1 udp_forward = tonumber(user.udp_forward) or 1
if udp_forward == 1 then if udp_forward == 1 then
udp_param = "-u" udp_param = "-u"
end end
type = type:lower() type = type:lower()
bin = ln_run("/usr/bin/" .. type .. "-server", type .. "-server", "-c " .. config_file .. " " .. udp_param, log_path) bin = ln_run("/usr/bin/" .. type .. "-server", type .. "-server", "-c " .. config_file .. " " .. udp_param, log_path)
elseif type == "SS-Rust" then elseif type == "SS-Rust" then
config = require(require_dir .. "util_shadowsocks").gen_config_server(user) config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
bin = ln_run("/usr/bin/ssserver", "ssserver", "-c " .. config_file, log_path) bin = ln_run("/usr/bin/ssserver", "ssserver", "-c " .. config_file, log_path)
elseif type == "V2ray" then elseif type == "V2ray" then
config = require(require_dir .. "util_xray").gen_config_server(user) config = require(require_dir .. "util_xray").gen_config_server(user)
bin = ln_run(api.get_app_path("v2ray"), "v2ray", "run -c " .. config_file, log_path) bin = ln_run(api.get_app_path("v2ray"), "v2ray", "run -c " .. config_file, log_path)
elseif type == "Xray" then elseif type == "Xray" then
config = require(require_dir .. "util_xray").gen_config_server(user) config = require(require_dir .. "util_xray").gen_config_server(user)
bin = ln_run(api.get_app_path("xray"), "xray", "run -c " .. config_file, log_path) bin = ln_run(api.get_app_path("xray"), "xray", "run -c " .. config_file, log_path)
elseif type == "Trojan" then elseif type == "Trojan" then
config = require(require_dir .. "util_trojan").gen_config_server(user) config = require(require_dir .. "util_trojan").gen_config_server(user)
bin = ln_run("/usr/sbin/trojan", "trojan", "-c " .. config_file, log_path) bin = ln_run("/usr/sbin/trojan", "trojan", "-c " .. config_file, log_path)
elseif type == "Trojan-Plus" then elseif type == "Trojan-Plus" then
config = require(require_dir .. "util_trojan").gen_config_server(user) config = require(require_dir .. "util_trojan").gen_config_server(user)
bin = ln_run("/usr/sbin/trojan-plus", "trojan-plus", "-c " .. config_file, log_path) bin = ln_run("/usr/sbin/trojan-plus", "trojan-plus", "-c " .. config_file, log_path)
elseif type == "Trojan-Go" then elseif type == "Trojan-Go" then
config = require(require_dir .. "util_trojan").gen_config_server(user) config = require(require_dir .. "util_trojan").gen_config_server(user)
bin = ln_run(api.get_app_path("trojan-go"), "trojan-go", "-config " .. config_file, log_path) bin = ln_run(api.get_app_path("trojan-go"), "trojan-go", "-config " .. config_file, log_path)
elseif type == "Brook" then elseif type == "Brook" then
local brook_protocol = user.protocol local brook_protocol = user.protocol
local brook_password = user.password local brook_password = user.password
local brook_path = user.ws_path or "/ws" local brook_path = user.ws_path or "/ws"
local brook_path_arg = "" local brook_path_arg = ""
if brook_protocol == "wsserver" and brook_path then if brook_protocol == "wsserver" and brook_path then
brook_path_arg = " --path " .. brook_path brook_path_arg = " --path " .. brook_path
end end
bin = ln_run(api.get_app_path("brook"), "brook_" .. id, string.format("--debug %s -l :%s -p %s%s", brook_protocol, port, brook_password, brook_path_arg), log_path) bin = ln_run(api.get_app_path("brook"), "brook_" .. id, string.format("--debug %s -l :%s -p %s%s", brook_protocol, port, brook_password, brook_path_arg), log_path)
elseif type == "Hysteria" then elseif type == "Hysteria" then
config = require(require_dir .. "util_hysteria").gen_config_server(user) config = require(require_dir .. "util_hysteria").gen_config_server(user)
bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path) bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path)
end end
if next(config) then if next(config) then
local f, err = io.open(config_file, "w") local f, err = io.open(config_file, "w")
if f and err == nil then if f and err == nil then
f:write(jsonc.stringify(config, 1)) f:write(jsonc.stringify(config, 1))
f:close() f:close()
end end
log(string.format("%s %s 生成配置文件并运行 - %s", remarks, port, config_file)) log(string.format("%s %s 生成配置文件并运行 - %s", remarks, port, config_file))
end end
if bin then if bin then
cmd(bin) cmd(bin)
end end
local bind_local = user.bind_local or 0 local bind_local = user.bind_local or 0
if bind_local and tonumber(bind_local) ~= 1 then if bind_local and tonumber(bind_local) ~= 1 then
if nft_flag == "0" then if nft_flag == "0" then
ipt(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks)) ipt(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
ip6t(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks)) ip6t(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
if udp_forward == 1 then if udp_forward == 1 then
ipt(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks)) ipt(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
ip6t(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks)) ip6t(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
end end
else else
cmd(string.format('nft add rule inet fw4 PSW-SERVER meta l4proto tcp tcp dport {%s} accept', port)) cmd(string.format('nft add rule inet fw4 PSW-SERVER meta l4proto tcp tcp dport {%s} accept', port))
if udp_forward == 1 then if udp_forward == 1 then
cmd(string.format('nft add rule inet fw4 PSW-SERVER meta l4proto udp udp dport {%s} accept', port)) cmd(string.format('nft add rule inet fw4 PSW-SERVER meta l4proto udp udp dport {%s} accept', port))
end end
end end
end end
end end
end) end)
gen_include() gen_include()
end end
local function stop() local function stop()
cmd(string.format("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/' | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1", CONFIG_PATH)) cmd(string.format("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/' | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1", CONFIG_PATH))
if nft_flag == "0" then if nft_flag == "0" then
ipt("-D INPUT -j PSW-SERVER 2>/dev/null") ipt("-D INPUT -j PSW-SERVER 2>/dev/null")
ipt("-F PSW-SERVER 2>/dev/null") ipt("-F PSW-SERVER 2>/dev/null")
ipt("-X PSW-SERVER 2>/dev/null") ipt("-X PSW-SERVER 2>/dev/null")
ip6t("-D INPUT -j PSW-SERVER 2>/dev/null") ip6t("-D INPUT -j PSW-SERVER 2>/dev/null")
ip6t("-F PSW-SERVER 2>/dev/null") ip6t("-F PSW-SERVER 2>/dev/null")
ip6t("-X PSW-SERVER 2>/dev/null") ip6t("-X PSW-SERVER 2>/dev/null")
else else
nft_cmd="handles=$(nft -a list chain inet fw4 input | grep -E \"PSW-SERVER\" | awk -F '# handle ' '{print$2}')\n for handle in $handles; do\n nft delete rule inet fw4 input handle ${handle} 2>/dev/null\n done" nft_cmd="handles=$(nft -a list chain inet fw4 input | grep -E \"PSW-SERVER\" | awk -F '# handle ' '{print$2}')\n for handle in $handles; do\n nft delete rule inet fw4 input handle ${handle} 2>/dev/null\n done"
cmd(nft_cmd) cmd(nft_cmd)
cmd("nft flush chain inet fw4 PSW-SERVER 2>/dev/null") cmd("nft flush chain inet fw4 PSW-SERVER 2>/dev/null")
cmd("nft delete chain inet fw4 PSW-SERVER 2>/dev/null") cmd("nft delete chain inet fw4 PSW-SERVER 2>/dev/null")
end end
cmd(string.format("rm -rf %s %s /tmp/etc/%s.include", CONFIG_PATH, LOG_APP_FILE, CONFIG)) cmd(string.format("rm -rf %s %s /tmp/etc/%s.include", CONFIG_PATH, LOG_APP_FILE, CONFIG))
end end
if action then if action then
if action == "start" then if action == "start" then
start() start()
elseif action == "stop" then elseif action == "stop" then
stop() stop()
end end
end end

View File

@ -4,116 +4,115 @@ local uci = api.uci
local jsonc = api.jsonc local jsonc = api.jsonc
function gen_config_server(node) function gen_config_server(node)
local config = { local config = {
listen = ":" .. node.port, listen = ":" .. node.port,
protocol = node.protocol or "udp", protocol = node.protocol or "udp",
obfs = node.hysteria_obfs, obfs = node.hysteria_obfs,
cert = node.tls_certificateFile, cert = node.tls_certificateFile,
key = node.tls_keyFile, key = node.tls_keyFile,
auth = (node.hysteria_auth_type == "string") and { auth = (node.hysteria_auth_type == "string") and {
mode = "password", mode = "password",
config = { config = {
password = node.hysteria_auth_password password = node.hysteria_auth_password
} }
} or nil, } or nil,
disable_udp = (node.hysteria_udp == "0") and true or false, disable_udp = (node.hysteria_udp == "0") and true or false,
alpn = node.hysteria_alpn or nil, alpn = node.hysteria_alpn or nil,
up_mbps = tonumber(node.hysteria_up_mbps) or 10, up_mbps = tonumber(node.hysteria_up_mbps) or 10,
down_mbps = tonumber(node.hysteria_down_mbps) or 50, down_mbps = tonumber(node.hysteria_down_mbps) or 50,
recv_window_conn = (node.hysteria_recv_window_conn) and tonumber(node.hysteria_recv_window_conn) or nil, recv_window_conn = (node.hysteria_recv_window_conn) and tonumber(node.hysteria_recv_window_conn) or nil,
recv_window = (node.hysteria_recv_window) and tonumber(node.hysteria_recv_window) or nil, recv_window = (node.hysteria_recv_window) and tonumber(node.hysteria_recv_window) or nil,
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery) and true or false disable_mtu_discovery = (node.hysteria_disable_mtu_discovery) and true or false
} }
return config return config
end end
function gen_config(var) function gen_config(var)
local node_id = var["-node"] local node_id = var["-node"]
if not node_id then if not node_id then
print("-node 不能为空") print("-node 不能为空")
return return
end end
local node = uci:get_all("passwall", node_id) local node = uci:get_all("passwall", node_id)
local local_tcp_redir_port = var["-local_tcp_redir_port"] local local_tcp_redir_port = var["-local_tcp_redir_port"]
local local_udp_redir_port = var["-local_udp_redir_port"] local local_udp_redir_port = var["-local_udp_redir_port"]
local local_socks_address = var["-local_socks_address"] or "0.0.0.0" local local_socks_address = var["-local_socks_address"] or "0.0.0.0"
local local_socks_port = var["-local_socks_port"] local local_socks_port = var["-local_socks_port"]
local local_socks_username = var["-local_socks_username"] local local_socks_username = var["-local_socks_username"]
local local_socks_password = var["-local_socks_password"] local local_socks_password = var["-local_socks_password"]
local local_http_address = var["-local_http_address"] or "0.0.0.0" local local_http_address = var["-local_http_address"] or "0.0.0.0"
local local_http_port = var["-local_http_port"] local local_http_port = var["-local_http_port"]
local local_http_username = var["-local_http_username"] local local_http_username = var["-local_http_username"]
local local_http_password = var["-local_http_password"] local local_http_password = var["-local_http_password"]
local tcp_proxy_way = var["-tcp_proxy_way"] local tcp_proxy_way = var["-tcp_proxy_way"]
local server_host = var["-server_host"] or node.address local server_host = var["-server_host"] or node.address
local server_port = var["-server_port"] or node.port local server_port = var["-server_port"] or node.port
if api.is_ipv6(server_host) then if api.is_ipv6(server_host) then
server_host = api.get_ipv6_full(server_host) server_host = api.get_ipv6_full(server_host)
end end
local server = server_host .. ":" .. server_port local server = server_host .. ":" .. server_port
if (node.hysteria_hop) then if (node.hysteria_hop) then
server = server .. "," .. node.hysteria_hop server = server .. "," .. node.hysteria_hop
end end
local config = { local config = {
server = server, server = server,
protocol = node.protocol or "udp", protocol = node.protocol or "udp",
obfs = node.hysteria_obfs, obfs = node.hysteria_obfs,
auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil, auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil,
auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil, auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil,
alpn = node.hysteria_alpn or nil, alpn = node.hysteria_alpn or nil,
server_name = node.tls_serverName, server_name = node.tls_serverName,
insecure = (node.tls_allowInsecure == "1") and true or false, insecure = (node.tls_allowInsecure == "1") and true or false,
up_mbps = tonumber(node.hysteria_up_mbps) or 10, up_mbps = tonumber(node.hysteria_up_mbps) or 10,
down_mbps = tonumber(node.hysteria_down_mbps) or 50, down_mbps = tonumber(node.hysteria_down_mbps) or 50,
retry = -1, retry = -1,
retry_interval = 5, retry_interval = 5,
recv_window_conn = (node.hysteria_recv_window_conn) and tonumber(node.hysteria_recv_window_conn) or nil, recv_window_conn = (node.hysteria_recv_window_conn) and tonumber(node.hysteria_recv_window_conn) or nil,
recv_window = (node.hysteria_recv_window) and tonumber(node.hysteria_recv_window) or nil, recv_window = (node.hysteria_recv_window) and tonumber(node.hysteria_recv_window) or nil,
handshake_timeout = (node.hysteria_handshake_timeout) and tonumber(node.hysteria_handshake_timeout) or nil, handshake_timeout = (node.hysteria_handshake_timeout) and tonumber(node.hysteria_handshake_timeout) or nil,
idle_timeout = (node.hysteria_idle_timeout) and tonumber(node.hysteria_idle_timeout) or nil, idle_timeout = (node.hysteria_idle_timeout) and tonumber(node.hysteria_idle_timeout) or nil,
hop_interval = (node.hysteria_hop_interval) and tonumber(node.hysteria_hop_interval) or nil, hop_interval = (node.hysteria_hop_interval) and tonumber(node.hysteria_hop_interval) or nil,
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery) and true or false, disable_mtu_discovery = (node.hysteria_disable_mtu_discovery) and true or false,
fast_open = (node.fast_open == "1") and true or false, fast_open = (node.fast_open == "1") and true or false,
socks5 = (local_socks_address and local_socks_port) and { socks5 = (local_socks_address and local_socks_port) and {
listen = local_socks_address .. ":" .. local_socks_port, listen = local_socks_address .. ":" .. local_socks_port,
timeout = 300, timeout = 300,
disable_udp = false, disable_udp = false,
user = (local_socks_username and local_socks_password) and local_socks_username, user = (local_socks_username and local_socks_password) and local_socks_username,
password = (local_socks_username and local_socks_password) and local_socks_password, password = (local_socks_username and local_socks_password) and local_socks_password,
} or nil, } or nil,
http = (local_http_address and local_http_port) and { http = (local_http_address and local_http_port) and {
listen = local_http_address .. ":" .. local_http_port, listen = local_http_address .. ":" .. local_http_port,
timeout = 300, timeout = 300,
disable_udp = false, disable_udp = false,
user = (local_http_username and local_http_password) and local_http_username, user = (local_http_username and local_http_password) and local_http_username,
password = (local_http_username and local_http_password) and local_http_password, password = (local_http_username and local_http_password) and local_http_password,
} or nil, } or nil,
redirect_tcp = ("redirect" == tcp_proxy_way and local_tcp_redir_port) and { redirect_tcp = ("redirect" == tcp_proxy_way and local_tcp_redir_port) and {
listen = "0.0.0.0:" .. local_tcp_redir_port, listen = "0.0.0.0:" .. local_tcp_redir_port,
timeout = 300 timeout = 300
} or nil, } or nil,
tproxy_tcp = ("tproxy" == tcp_proxy_way and local_tcp_redir_port) and { tproxy_tcp = ("tproxy" == tcp_proxy_way and local_tcp_redir_port) and {
listen = "0.0.0.0:" .. local_tcp_redir_port, listen = "0.0.0.0:" .. local_tcp_redir_port,
timeout = 300 timeout = 300
} or nil, } or nil,
tproxy_udp = (local_udp_redir_port) and { tproxy_udp = (local_udp_redir_port) and {
listen = "0.0.0.0:" .. local_udp_redir_port, listen = "0.0.0.0:" .. local_udp_redir_port,
timeout = 60 timeout = 60
} or nil } or nil
} }
return jsonc.stringify(config, 1) return jsonc.stringify(config, 1)
end end
_G.gen_config = gen_config _G.gen_config = gen_config
if arg[1] then if arg[1] then
local func =_G[arg[1]] local func =_G[arg[1]]
if func then if func then
print(func(api.get_function_args(arg))) print(func(api.get_function_args(arg)))
end end
end end

View File

@ -4,36 +4,36 @@ local uci = api.uci
local jsonc = api.jsonc local jsonc = api.jsonc
function gen_config(var) function gen_config(var)
local node_id = var["-node"] local node_id = var["-node"]
if not node_id then if not node_id then
print("-node 不能为空") print("-node 不能为空")
return return
end end
local node = uci:get_all("passwall", node_id) local node = uci:get_all("passwall", node_id)
local run_type = var["-run_type"] local run_type = var["-run_type"]
local local_addr = var["-local_addr"] local local_addr = var["-local_addr"]
local local_port = var["-local_port"] local local_port = var["-local_port"]
local server_host = var["-server_host"] or node.address local server_host = var["-server_host"] or node.address
local server_port = var["-server_port"] or node.port local server_port = var["-server_port"] or node.port
if api.is_ipv6(server_host) then if api.is_ipv6(server_host) then
server_host = api.get_ipv6_full(server_host) server_host = api.get_ipv6_full(server_host)
end end
local server = server_host .. ":" .. server_port local server = server_host .. ":" .. server_port
local config = { local config = {
listen = run_type .. "://" .. local_addr .. ":" .. local_port, listen = run_type .. "://" .. local_addr .. ":" .. local_port,
proxy = node.protocol .. "://" .. node.username .. ":" .. node.password .. "@" .. server proxy = node.protocol .. "://" .. node.username .. ":" .. node.password .. "@" .. server
} }
return jsonc.stringify(config, 1) return jsonc.stringify(config, 1)
end end
_G.gen_config = gen_config _G.gen_config = gen_config
if arg[1] then if arg[1] then
local func =_G[arg[1]] local func =_G[arg[1]]
if func then if func then
print(func(api.get_function_args(arg))) print(func(api.get_function_args(arg)))
end end
end end

View File

@ -4,141 +4,141 @@ local uci = api.uci
local jsonc = api.jsonc local jsonc = api.jsonc
function gen_config_server(node) function gen_config_server(node)
local config = {} local config = {}
config.server_port = tonumber(node.port) config.server_port = tonumber(node.port)
config.password = node.password config.password = node.password
config.timeout = tonumber(node.timeout) config.timeout = tonumber(node.timeout)
config.fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false config.fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false
config.method = node.method config.method = node.method
if node.type == "SS-Rust" then if node.type == "SS-Rust" then
config.server = "::" config.server = "::"
config.mode = "tcp_and_udp" config.mode = "tcp_and_udp"
else else
config.server = {"[::0]", "0.0.0.0"} config.server = {"[::0]", "0.0.0.0"}
end end
if node.type == "SSR" then if node.type == "SSR" then
config.protocol = node.protocol config.protocol = node.protocol
config.protocol_param = node.protocol_param config.protocol_param = node.protocol_param
config.obfs = node.obfs config.obfs = node.obfs
config.obfs_param = node.obfs_param config.obfs_param = node.obfs_param
end end
return config return config
end end
function gen_config(var) function gen_config(var)
local node_id = var["-node"] local node_id = var["-node"]
if not node_id then if not node_id then
print("-node 不能为空") print("-node 不能为空")
return return
end end
local node = uci:get_all("passwall", node_id) local node = uci:get_all("passwall", node_id)
local server_host = var["-server_host"] or node.address local server_host = var["-server_host"] or node.address
local server_port = var["-server_port"] or node.port local server_port = var["-server_port"] or node.port
local local_addr = var["-local_addr"] local local_addr = var["-local_addr"]
local local_port = var["-local_port"] local local_port = var["-local_port"]
local mode = var["-mode"] local mode = var["-mode"]
local local_socks_address = var["-local_socks_address"] or "0.0.0.0" local local_socks_address = var["-local_socks_address"] or "0.0.0.0"
local local_socks_port = var["-local_socks_port"] local local_socks_port = var["-local_socks_port"]
local local_socks_username = var["-local_socks_username"] local local_socks_username = var["-local_socks_username"]
local local_socks_password = var["-local_socks_password"] local local_socks_password = var["-local_socks_password"]
local local_http_address = var["-local_http_address"] or "0.0.0.0" local local_http_address = var["-local_http_address"] or "0.0.0.0"
local local_http_port = var["-local_http_port"] local local_http_port = var["-local_http_port"]
local local_http_username = var["-local_http_username"] local local_http_username = var["-local_http_username"]
local local_http_password = var["-local_http_password"] local local_http_password = var["-local_http_password"]
local local_tcp_redir_port = var["-local_tcp_redir_port"] local local_tcp_redir_port = var["-local_tcp_redir_port"]
local local_tcp_redir_address = var["-local_tcp_redir_address"] or "0.0.0.0" local local_tcp_redir_address = var["-local_tcp_redir_address"] or "0.0.0.0"
local local_udp_redir_port = var["-local_udp_redir_port"] local local_udp_redir_port = var["-local_udp_redir_port"]
local local_udp_redir_address = var["-local_udp_redir_address"] or "0.0.0.0" local local_udp_redir_address = var["-local_udp_redir_address"] or "0.0.0.0"
if api.is_ipv6(server_host) then if api.is_ipv6(server_host) then
server_host = api.get_ipv6_only(server_host) server_host = api.get_ipv6_only(server_host)
end end
local server = server_host local server = server_host
local config = { local config = {
server = server, server = server,
server_port = tonumber(server_port), server_port = tonumber(server_port),
local_address = local_addr, local_address = local_addr,
local_port = tonumber(local_port), local_port = tonumber(local_port),
password = node.password, password = node.password,
method = node.method, method = node.method,
timeout = tonumber(node.timeout), timeout = tonumber(node.timeout),
fast_open = (node.tcp_fast_open and node.tcp_fast_open == "true") and true or false, fast_open = (node.tcp_fast_open and node.tcp_fast_open == "true") and true or false,
reuse_port = true, reuse_port = true,
tcp_tproxy = var["-tcp_tproxy"] and true or nil tcp_tproxy = var["-tcp_tproxy"] and true or nil
} }
if node.type == "SS" then if node.type == "SS" then
if node.plugin and node.plugin ~= "none" then if node.plugin and node.plugin ~= "none" then
config.plugin = node.plugin config.plugin = node.plugin
config.plugin_opts = node.plugin_opts or nil config.plugin_opts = node.plugin_opts or nil
end end
config.mode = mode config.mode = mode
elseif node.type == "SSR" then elseif node.type == "SSR" then
config.protocol = node.protocol config.protocol = node.protocol
config.protocol_param = node.protocol_param config.protocol_param = node.protocol_param
config.obfs = node.obfs config.obfs = node.obfs
config.obfs_param = node.obfs_param config.obfs_param = node.obfs_param
elseif node.type == "SS-Rust" then elseif node.type == "SS-Rust" then
config = { config = {
servers = { servers = {
{ {
address = server, address = server,
port = tonumber(server_port), port = tonumber(server_port),
method = node.method, method = node.method,
password = node.password, password = node.password,
timeout = tonumber(node.timeout), timeout = tonumber(node.timeout),
plugin = (node.plugin and node.plugin ~= "none") and node.plugin or nil, plugin = (node.plugin and node.plugin ~= "none") and node.plugin or nil,
plugin_opts = (node.plugin and node.plugin ~= "none") and node.plugin_opts or nil plugin_opts = (node.plugin and node.plugin ~= "none") and node.plugin_opts or nil
} }
}, },
locals = {}, locals = {},
fast_open = (node.tcp_fast_open and node.tcp_fast_open == "true") and true or false fast_open = (node.tcp_fast_open and node.tcp_fast_open == "true") and true or false
} }
if local_socks_address and local_socks_port then if local_socks_address and local_socks_port then
table.insert(config.locals, { table.insert(config.locals, {
local_address = local_socks_address, local_address = local_socks_address,
local_port = tonumber(local_socks_port), local_port = tonumber(local_socks_port),
mode = "tcp_and_udp" mode = "tcp_and_udp"
}) })
end end
if local_http_address and local_http_port then if local_http_address and local_http_port then
table.insert(config.locals, { table.insert(config.locals, {
protocol = "http", protocol = "http",
local_address = local_http_address, local_address = local_http_address,
local_port = tonumber(local_http_port) local_port = tonumber(local_http_port)
}) })
end end
if local_tcp_redir_address and local_tcp_redir_port then if local_tcp_redir_address and local_tcp_redir_port then
table.insert(config.locals, { table.insert(config.locals, {
protocol = "redir", protocol = "redir",
mode = "tcp_only", mode = "tcp_only",
tcp_redir = var["-tcp_tproxy"] and "tproxy" or nil, tcp_redir = var["-tcp_tproxy"] and "tproxy" or nil,
local_address = local_tcp_redir_address, local_address = local_tcp_redir_address,
local_port = tonumber(local_tcp_redir_port) local_port = tonumber(local_tcp_redir_port)
}) })
end end
if local_udp_redir_address and local_udp_redir_port then if local_udp_redir_address and local_udp_redir_port then
table.insert(config.locals, { table.insert(config.locals, {
protocol = "redir", protocol = "redir",
mode = "udp_only", mode = "udp_only",
local_address = local_udp_redir_address, local_address = local_udp_redir_address,
local_port = tonumber(local_udp_redir_port) local_port = tonumber(local_udp_redir_port)
}) })
end end
end end
return jsonc.stringify(config, 1) return jsonc.stringify(config, 1)
end end
_G.gen_config = gen_config _G.gen_config = gen_config
if arg[1] then if arg[1] then
local func =_G[arg[1]] local func =_G[arg[1]]
if func then if func then
print(func(api.get_function_args(arg))) print(func(api.get_function_args(arg)))
end end
end end

View File

@ -4,155 +4,155 @@ local uci = api.uci
local json = api.jsonc local json = api.jsonc
function gen_config_server(node) function gen_config_server(node)
local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA" local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384" local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384"
local config = { local config = {
run_type = "server", run_type = "server",
local_addr = "::", local_addr = "::",
local_port = tonumber(node.port), local_port = tonumber(node.port),
remote_addr = (node.remote_enable == "1" and node.remote_address) and node.remote_address or nil, remote_addr = (node.remote_enable == "1" and node.remote_address) and node.remote_address or nil,
remote_port = (node.remote_enable == "1" and node.remote_port) and tonumber(node.remote_port) or nil, remote_port = (node.remote_enable == "1" and node.remote_port) and tonumber(node.remote_port) or nil,
password = node.uuid, password = node.uuid,
log_level = (node.log and node.log == "1") and tonumber(node.loglevel) or 5, log_level = (node.log and node.log == "1") and tonumber(node.loglevel) or 5,
ssl = { ssl = {
cert = node.tls_certificateFile, cert = node.tls_certificateFile,
key = node.tls_keyFile, key = node.tls_keyFile,
key_password = "", key_password = "",
cipher = cipher, cipher = cipher,
cipher_tls13 = cipher13, cipher_tls13 = cipher13,
prefer_server_cipher = true, prefer_server_cipher = true,
reuse_session = true, reuse_session = true,
session_ticket = (node.tls_sessionTicket == "1") and true or false, session_ticket = (node.tls_sessionTicket == "1") and true or false,
session_timeout = 600, session_timeout = 600,
plain_http_response = "", plain_http_response = "",
curves = "", curves = "",
dhparam = "" dhparam = ""
}, },
tcp = { tcp = {
prefer_ipv4 = false, prefer_ipv4 = false,
no_delay = true, no_delay = true,
keep_alive = true, keep_alive = true,
reuse_port = false, reuse_port = false,
fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false, fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false,
fast_open_qlen = 20 fast_open_qlen = 20
} }
} }
if node.type == "Trojan-Go" then if node.type == "Trojan-Go" then
config.ssl.cipher = nil config.ssl.cipher = nil
config.ssl.cipher_tls13 = nil config.ssl.cipher_tls13 = nil
config.udp_timeout = 60 config.udp_timeout = 60
config.disable_http_check = true config.disable_http_check = true
config.transport_plugin = ((node.tls == nil or node.tls ~= "1") and node.trojan_transport == "original") and { config.transport_plugin = ((node.tls == nil or node.tls ~= "1") and node.trojan_transport == "original") and {
enabled = node.plugin_type ~= nil, enabled = node.plugin_type ~= nil,
type = node.plugin_type or "plaintext", type = node.plugin_type or "plaintext",
command = node.plugin_type ~= "plaintext" and node.plugin_cmd or nil, command = node.plugin_type ~= "plaintext" and node.plugin_cmd or nil,
option = node.plugin_type ~= "plaintext" and node.plugin_option or nil, option = node.plugin_type ~= "plaintext" and node.plugin_option or nil,
arg = node.plugin_type ~= "plaintext" and { node.plugin_arg } or nil, arg = node.plugin_type ~= "plaintext" and { node.plugin_arg } or nil,
env = {} env = {}
} or nil } or nil
config.websocket = (node.trojan_transport == 'ws') and { config.websocket = (node.trojan_transport == 'ws') and {
enabled = true, enabled = true,
path = node.ws_path or "/", path = node.ws_path or "/",
host = node.ws_host or "" host = node.ws_host or ""
} or nil } or nil
config.shadowsocks = (node.ss_aead == "1") and { config.shadowsocks = (node.ss_aead == "1") and {
enabled = true, enabled = true,
method = node.ss_aead_method or "aes_128_gcm", method = node.ss_aead_method or "aes_128_gcm",
password = node.ss_aead_pwd or "" password = node.ss_aead_pwd or ""
} or nil } or nil
end end
return config return config
end end
function gen_config(var) function gen_config(var)
local node_id = var["-node"] local node_id = var["-node"]
if not node_id then if not node_id then
print("-node 不能为空") print("-node 不能为空")
return return
end end
local node = uci:get_all("passwall", node_id) local node = uci:get_all("passwall", node_id)
local run_type = var["-run_type"] local run_type = var["-run_type"]
local local_addr = var["-local_addr"] local local_addr = var["-local_addr"]
local local_port = var["-local_port"] local local_port = var["-local_port"]
local server_host = var["-server_host"] or node.address local server_host = var["-server_host"] or node.address
local server_port = var["-server_port"] or node.port local server_port = var["-server_port"] or node.port
local loglevel = var["-loglevel"] or 2 local loglevel = var["-loglevel"] or 2
local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA" local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384" local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384"
if api.is_ipv6(server_host) then if api.is_ipv6(server_host) then
server_host = api.get_ipv6_only(server_host) server_host = api.get_ipv6_only(server_host)
end end
local server = server_host local server = server_host
local trojan = { local trojan = {
run_type = run_type, run_type = run_type,
local_addr = local_addr, local_addr = local_addr,
local_port = tonumber(local_port), local_port = tonumber(local_port),
remote_addr = server, remote_addr = server,
remote_port = tonumber(server_port), remote_port = tonumber(server_port),
password = {node.password}, password = {node.password},
log_level = tonumber(loglevel), log_level = tonumber(loglevel),
ssl = { ssl = {
verify = (node.tls_allowInsecure ~= "1") and true or false, verify = (node.tls_allowInsecure ~= "1") and true or false,
verify_hostname = true, verify_hostname = true,
cert = nil, cert = nil,
cipher = cipher, cipher = cipher,
cipher_tls13 = cipher13, cipher_tls13 = cipher13,
sni = node.tls_serverName or server, sni = node.tls_serverName or server,
alpn = {"h2", "http/1.1"}, alpn = {"h2", "http/1.1"},
reuse_session = true, reuse_session = true,
session_ticket = (node.tls_sessionTicket and node.tls_sessionTicket == "1") and true or false, session_ticket = (node.tls_sessionTicket and node.tls_sessionTicket == "1") and true or false,
curves = "" curves = ""
}, },
udp_timeout = 60, udp_timeout = 60,
tcp = { tcp = {
use_tproxy = (node.type == "Trojan-Plus" and var["-use_tproxy"]) and true or nil, use_tproxy = (node.type == "Trojan-Plus" and var["-use_tproxy"]) and true or nil,
no_delay = true, no_delay = true,
keep_alive = true, keep_alive = true,
reuse_port = true, reuse_port = true,
fast_open = (node.tcp_fast_open == "true") and true or false, fast_open = (node.tcp_fast_open == "true") and true or false,
fast_open_qlen = 20 fast_open_qlen = 20
} }
} }
if node.type == "Trojan-Go" then if node.type == "Trojan-Go" then
trojan.ssl.cipher = nil trojan.ssl.cipher = nil
trojan.ssl.cipher_tls13 = nil trojan.ssl.cipher_tls13 = nil
trojan.ssl.fingerprint = (node.fingerprint ~= "disable") and node.fingerprint or "" trojan.ssl.fingerprint = (node.fingerprint ~= "disable") and node.fingerprint or ""
trojan.ssl.alpn = (node.trojan_transport == 'ws') and {} or {"h2", "http/1.1"} trojan.ssl.alpn = (node.trojan_transport == 'ws') and {} or {"h2", "http/1.1"}
if node.tls ~= "1" and node.trojan_transport == "original" then trojan.ssl = nil end if node.tls ~= "1" and node.trojan_transport == "original" then trojan.ssl = nil end
trojan.transport_plugin = ((not node.tls or node.tls ~= "1") and node.trojan_transport == "original") and { trojan.transport_plugin = ((not node.tls or node.tls ~= "1") and node.trojan_transport == "original") and {
enabled = node.plugin_type ~= nil, enabled = node.plugin_type ~= nil,
type = node.plugin_type or "plaintext", type = node.plugin_type or "plaintext",
command = node.plugin_type ~= "plaintext" and node.plugin_cmd or nil, command = node.plugin_type ~= "plaintext" and node.plugin_cmd or nil,
option = node.plugin_type ~= "plaintext" and node.plugin_option or nil, option = node.plugin_type ~= "plaintext" and node.plugin_option or nil,
arg = node.plugin_type ~= "plaintext" and { node.plugin_arg } or nil, arg = node.plugin_type ~= "plaintext" and { node.plugin_arg } or nil,
env = {} env = {}
} or nil } or nil
trojan.websocket = (node.trojan_transport == 'ws') and { trojan.websocket = (node.trojan_transport == 'ws') and {
enabled = true, enabled = true,
path = node.ws_path or "/", path = node.ws_path or "/",
host = node.ws_host or (node.tls_serverName or server) host = node.ws_host or (node.tls_serverName or server)
} or nil } or nil
trojan.shadowsocks = (node.ss_aead == "1") and { trojan.shadowsocks = (node.ss_aead == "1") and {
enabled = true, enabled = true,
method = node.ss_aead_method or "aes_128_gcm", method = node.ss_aead_method or "aes_128_gcm",
password = node.ss_aead_pwd or "" password = node.ss_aead_pwd or ""
} or nil } or nil
trojan.mux = (node.smux == "1") and { trojan.mux = (node.smux == "1") and {
enabled = true, enabled = true,
concurrency = tonumber(node.mux_concurrency), concurrency = tonumber(node.mux_concurrency),
idle_timeout = tonumber(node.smux_idle_timeout) idle_timeout = tonumber(node.smux_idle_timeout)
} or nil } or nil
end end
return json.stringify(trojan, 1) return json.stringify(trojan, 1)
end end
_G.gen_config = gen_config _G.gen_config = gen_config
if arg[1] then if arg[1] then
local func =_G[arg[1]] local func =_G[arg[1]]
if func then if func then
print(func(api.get_function_args(arg))) print(func(api.get_function_args(arg)))
end end
end end

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,6 @@ local version = {}
if (inProgressCount === 0) { if (inProgressCount === 0) {
window.onbeforeunload = undefined; window.onbeforeunload = undefined;
} }
} }
function onUpdateSuccess(btn) { function onUpdateSuccess(btn) {

View File

@ -10,6 +10,7 @@ local api = require "luci.passwall.api"
window.location.href = '<%=api.url("autoswitch_add_node")%>' + "?key=" + key; window.location.href = '<%=api.url("autoswitch_add_node")%>' + "?key=" + key;
} }
} }
function remove_node_by_key() { function remove_node_by_key() {
var key = prompt("<%:Please enter the node keyword, pay attention to distinguish between spaces, uppercase and lowercase.%>", ""); var key = prompt("<%:Please enter the node keyword, pay attention to distinguish between spaces, uppercase and lowercase.%>", "");
if (key) { if (key) {

View File

@ -14,6 +14,7 @@ local api = require "luci.passwall.api"
} }
); );
} }
XHR.poll(5, '<%=api.url("get_log")%>', null, XHR.poll(5, '<%=api.url("get_log")%>', null,
function(x, data) { function(x, data) {
if(x && x.status == 200) { if(x && x.status == 200) {

View File

@ -13,7 +13,7 @@ local api = require "luci.passwall.api"
z-index: 99; z-index: 99;
text-align: center; text-align: center;
background: white; background: white;
box-shadow: darkgrey 10px 10px 30px 5px; box-shadow: darkgrey 10px 10px 30px 5px;
padding: 30px 15px; padding: 30px 15px;
} }
</style> </style>

View File

@ -55,6 +55,7 @@ local has_xray = api.is_finded("xray")
return ''; return '';
return b64decsafe(v); return b64decsafe(v);
} }
function parseNodeUrl(url) { function parseNodeUrl(url) {
var m = url.match(/^(([^:\/?#]+:)?(?:\/\/((?:([^\/?#:]*)([^\/?#:]*)@)?([^\/?#:]*)(?::([^\/?#:]*))?)))?([^?#]*)(\?[^#]*)?(#.*)?$/), var m = url.match(/^(([^:\/?#]+:)?(?:\/\/((?:([^\/?#:]*)([^\/?#:]*)@)?([^\/?#:]*)(?::([^\/?#:]*))?)))?([^?#]*)(\?[^#]*)?(#.*)?$/),
r = { r = {

View File

@ -9,8 +9,8 @@ table th, .table .th {
table td, .table .td { table td, .table .td {
text-align: center; text-align: center;
/* white-space: nowrap; */ /* white-space: nowrap; */
word-break: keep-all; word-break: keep-all;
} }
#set_node_div { #set_node_div {
@ -22,7 +22,7 @@ table td, .table .td {
z-index: 99; z-index: 99;
text-align: center; text-align: center;
background: white; background: white;
box-shadow: darkgrey 10px 10px 30px 5px; box-shadow: darkgrey 10px 10px 30px 5px;
} }
._now_use { ._now_use {

View File

@ -14,6 +14,7 @@ local api = require "luci.passwall.api"
} }
); );
} }
XHR.poll(3, '<%=api.url("server_get_log")%>', null, XHR.poll(3, '<%=api.url("server_get_log")%>', null,
function(x, data) { function(x, data) {
if(x && x.status == 200) { if(x && x.status == 200) {

View File

@ -33,133 +33,133 @@ local excluded_domain = {}
local excluded_domain_str = "!" local excluded_domain_str = "!"
local function log(...) local function log(...)
if NO_LOGIC_LOG == "1" then if NO_LOGIC_LOG == "1" then
return return
end end
local f, err = io.open(LOG_FILE, "a") local f, err = io.open(LOG_FILE, "a")
if f and err == nil then if f and err == nil then
local str = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ") local str = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
f:write(str .. "\n") f:write(str .. "\n")
f:close() f:close()
end end
end end
local function check_dns(domain, dns) local function check_dns(domain, dns)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return false return false
end end
if not dns then if not dns then
return return
end end
for k,v in ipairs(list1[domain].dns) do for k,v in ipairs(list1[domain].dns) do
if dns == v then if dns == v then
return true return true
end end
end end
return false return false
end end
local function check_ipset(domain, ipset) local function check_ipset(domain, ipset)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return false return false
end end
if not ipset then if not ipset then
return return
end end
for k,v in ipairs(list1[domain].ipsets) do for k,v in ipairs(list1[domain].ipsets) do
if ipset == v then if ipset == v then
return true return true
end end
end end
return false return false
end end
local function set_domain_address(domain, address) local function set_domain_address(domain, address)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return return
end end
if not list1[domain] then if not list1[domain] then
list1[domain] = { list1[domain] = {
dns = {}, dns = {},
ipsets = {} ipsets = {}
} }
end end
if not list1[domain].address then if not list1[domain].address then
list1[domain].address = address list1[domain].address = address
end end
end end
local function set_domain_dns(domain, dns) local function set_domain_dns(domain, dns)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return return
end end
if not dns then if not dns then
return return
end end
if not list1[domain] then if not list1[domain] then
list1[domain] = { list1[domain] = {
dns = {}, dns = {},
ipsets = {} ipsets = {}
} }
end end
for line in string.gmatch(dns, '[^' .. "," .. ']+') do for line in string.gmatch(dns, '[^' .. "," .. ']+') do
if not check_dns(domain, line) then if not check_dns(domain, line) then
table.insert(list1[domain].dns, line) table.insert(list1[domain].dns, line)
end end
end end
end end
local function set_domain_ipset(domain, ipset) local function set_domain_ipset(domain, ipset)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return return
end end
if not ipset then if not ipset then
return return
end end
if not list1[domain] then if not list1[domain] then
list1[domain] = { list1[domain] = {
dns = {}, dns = {},
ipsets = {} ipsets = {}
} }
end end
for line in string.gmatch(ipset, '[^' .. "," .. ']+') do for line in string.gmatch(ipset, '[^' .. "," .. ']+') do
if not check_ipset(domain, line) then if not check_ipset(domain, line) then
table.insert(list1[domain].ipsets, line) table.insert(list1[domain].ipsets, line)
end end
end end
end end
local function add_excluded_domain(domain) local function add_excluded_domain(domain)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return return
end end
table.insert(excluded_domain, domain) table.insert(excluded_domain, domain)
excluded_domain_str = excluded_domain_str .. "|" .. domain excluded_domain_str = excluded_domain_str .. "|" .. domain
end end
local function check_excluded_domain(domain) local function check_excluded_domain(domain)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return false return false
end end
for k,v in ipairs(excluded_domain) do for k,v in ipairs(excluded_domain) do
if domain:find(v) then if domain:find(v) then
return true return true
end end
end end
return false return false
end end
local cache_text = "" local cache_text = ""
local new_rules = luci.sys.exec("echo -n $(find /usr/share/passwall/rules -type f | xargs md5sum)") local new_rules = luci.sys.exec("echo -n $(find /usr/share/passwall/rules -type f | xargs md5sum)")
local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. REMOTE_FAKEDNS .. CHNROUTE_MODE_DEFAULT_DNS .. CHINADNS_DNS .. PROXY_MODE .. NO_PROXY_IPV6 .. new_rules .. NFTFLAG local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. REMOTE_FAKEDNS .. CHNROUTE_MODE_DEFAULT_DNS .. CHINADNS_DNS .. PROXY_MODE .. NO_PROXY_IPV6 .. new_rules .. NFTFLAG
if fs.access(CACHE_TEXT_FILE) then if fs.access(CACHE_TEXT_FILE) then
for line in io.lines(CACHE_TEXT_FILE) do for line in io.lines(CACHE_TEXT_FILE) do
cache_text = line cache_text = line
end end
end end
if cache_text ~= new_text then if cache_text ~= new_text then
api.remove(CACHE_DNS_PATH .. "*") api.remove(CACHE_DNS_PATH .. "*")
end end
local global = PROXY_MODE:find("global") local global = PROXY_MODE:find("global")
@ -170,252 +170,252 @@ local only_global
local dnsmasq_default_dns local dnsmasq_default_dns
if CHNROUTE_MODE_DEFAULT_DNS ~= "nil" and chnlist then if CHNROUTE_MODE_DEFAULT_DNS ~= "nil" and chnlist then
if CHNROUTE_MODE_DEFAULT_DNS == "remote" then if CHNROUTE_MODE_DEFAULT_DNS == "remote" then
dnsmasq_default_dns = TUN_DNS dnsmasq_default_dns = TUN_DNS
end end
if CHNROUTE_MODE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then if CHNROUTE_MODE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then
dnsmasq_default_dns = CHINADNS_DNS dnsmasq_default_dns = CHINADNS_DNS
end end
end end
if global and (not returnhome and not chnlist and not gfwlist) then if global and (not returnhome and not chnlist and not gfwlist) then
--只有全局模式时 --只有全局模式时
dnsmasq_default_dns = TUN_DNS dnsmasq_default_dns = TUN_DNS
only_global = 1 only_global = 1
end end
local setflag_4= (NFTFLAG == "1") and "4#inet#fw4#" or "" local setflag_4= (NFTFLAG == "1") and "4#inet#fw4#" or ""
local setflag_6= (NFTFLAG == "1") and "6#inet#fw4#" or "" local setflag_6= (NFTFLAG == "1") and "6#inet#fw4#" or ""
if not fs.access(CACHE_DNS_PATH) then if not fs.access(CACHE_DNS_PATH) then
fs.mkdir("/tmp/dnsmasq.d") fs.mkdir("/tmp/dnsmasq.d")
fs.mkdir(CACHE_DNS_PATH) fs.mkdir(CACHE_DNS_PATH)
--屏蔽列表 --屏蔽列表
for line in io.lines("/usr/share/passwall/rules/block_host") do for line in io.lines("/usr/share/passwall/rules/block_host") do
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
set_domain_address(line, "0.0.0.0") set_domain_address(line, "0.0.0.0")
end end
end end
--始终用国内DNS解析节点域名 --始终用国内DNS解析节点域名
uci:foreach(appname, "nodes", function(t) uci:foreach(appname, "nodes", function(t)
local address = t.address local address = t.address
if datatypes.hostname(address) then if datatypes.hostname(address) then
set_domain_dns(address, LOCAL_DNS) set_domain_dns(address, LOCAL_DNS)
set_domain_ipset(address, setflag_4 .. "vpsiplist," .. setflag_6 .. "vpsiplist6") set_domain_ipset(address, setflag_4 .. "vpsiplist," .. setflag_6 .. "vpsiplist6")
end end
end) end)
log(string.format(" - 节点列表中的域名(vpsiplist)%s", LOCAL_DNS or "默认")) log(string.format(" - 节点列表中的域名(vpsiplist)%s", LOCAL_DNS or "默认"))
--始终用国内DNS解析直连白名单列表 --始终用国内DNS解析直连白名单列表
for line in io.lines("/usr/share/passwall/rules/direct_host") do for line in io.lines("/usr/share/passwall/rules/direct_host") do
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
add_excluded_domain(line) add_excluded_domain(line)
set_domain_dns(line, LOCAL_DNS) set_domain_dns(line, LOCAL_DNS)
set_domain_ipset(line, setflag_4 .. "whitelist," .. setflag_6 .. "whitelist6") set_domain_ipset(line, setflag_4 .. "whitelist," .. setflag_6 .. "whitelist6")
end end
end end
log(string.format(" - 域名白名单(whitelist)%s", LOCAL_DNS or "默认")) log(string.format(" - 域名白名单(whitelist)%s", LOCAL_DNS or "默认"))
local fwd_dns local fwd_dns
local ipset_flag local ipset_flag
local no_ipv6 local no_ipv6
--始终使用远程DNS解析代理黑名单列表 --始终使用远程DNS解析代理黑名单列表
for line in io.lines("/usr/share/passwall/rules/proxy_host") do for line in io.lines("/usr/share/passwall/rules/proxy_host") do
if line ~= "" and not line:find("#") then if line ~= "" and not line:find("#") then
add_excluded_domain(line) add_excluded_domain(line)
local ipset_flag = setflag_4 .. "blacklist," .. setflag_6 .. "blacklist6" local ipset_flag = setflag_4 .. "blacklist," .. setflag_6 .. "blacklist6"
if NO_PROXY_IPV6 == "1" then if NO_PROXY_IPV6 == "1" then
set_domain_address(line, "::") set_domain_address(line, "::")
ipset_flag = setflag_4 .. "blacklist" ipset_flag = setflag_4 .. "blacklist"
end end
if REMOTE_FAKEDNS == "1" then if REMOTE_FAKEDNS == "1" then
ipset_flag = nil ipset_flag = nil
end end
set_domain_dns(line, TUN_DNS) set_domain_dns(line, TUN_DNS)
set_domain_ipset(line, ipset_flag) set_domain_ipset(line, ipset_flag)
end end
end end
log(string.format(" - 代理域名表(blacklist)%s", TUN_DNS or "默认")) log(string.format(" - 代理域名表(blacklist)%s", TUN_DNS or "默认"))
--分流规则 --分流规则
if uci:get(appname, TCP_NODE, "protocol") == "_shunt" then if uci:get(appname, TCP_NODE, "protocol") == "_shunt" then
local t = uci:get_all(appname, TCP_NODE) local t = uci:get_all(appname, TCP_NODE)
local default_node_id = t["default_node"] or "_direct" local default_node_id = t["default_node"] or "_direct"
uci:foreach(appname, "shunt_rules", function(s) uci:foreach(appname, "shunt_rules", function(s)
local _node_id = t[s[".name"]] or "nil" local _node_id = t[s[".name"]] or "nil"
if _node_id ~= "nil" and _node_id ~= "_blackhole" then if _node_id ~= "nil" and _node_id ~= "_blackhole" then
if _node_id == "_default" then if _node_id == "_default" then
_node_id = default_node_id _node_id = default_node_id
end end
fwd_dns = nil fwd_dns = nil
ipset_flag = nil ipset_flag = nil
no_ipv6 = nil no_ipv6 = nil
if _node_id == "_direct" then if _node_id == "_direct" then
fwd_dns = LOCAL_DNS fwd_dns = LOCAL_DNS
ipset_flag = setflag_4 .. "whitelist," .. setflag_6 .. "whitelist6" ipset_flag = setflag_4 .. "whitelist," .. setflag_6 .. "whitelist6"
else else
fwd_dns = TUN_DNS fwd_dns = TUN_DNS
ipset_flag = setflag_4 .. "shuntlist," .. setflag_6 .. "shuntlist6" ipset_flag = setflag_4 .. "shuntlist," .. setflag_6 .. "shuntlist6"
if NO_PROXY_IPV6 == "1" then if NO_PROXY_IPV6 == "1" then
ipset_flag = setflag_4 .. "shuntlist" ipset_flag = setflag_4 .. "shuntlist"
no_ipv6 = true no_ipv6 = true
end end
if not only_global then if not only_global then
if REMOTE_FAKEDNS == "1" then if REMOTE_FAKEDNS == "1" then
ipset_flag = nil ipset_flag = nil
end end
end end
end end
local domain_list = s.domain_list or "" local domain_list = s.domain_list or ""
for line in string.gmatch(domain_list, "[^\r\n]+") do for line in string.gmatch(domain_list, "[^\r\n]+") do
if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("geosite:") and not line:find("ext:") then if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("geosite:") and not line:find("ext:") then
if line:find("domain:") or line:find("full:") then if line:find("domain:") or line:find("full:") then
line = string.match(line, ":([^:]+)$") line = string.match(line, ":([^:]+)$")
end end
add_excluded_domain(line) add_excluded_domain(line)
if no_ipv6 then if no_ipv6 then
set_domain_address(line, "::") set_domain_address(line, "::")
end end
set_domain_dns(line, fwd_dns) set_domain_dns(line, fwd_dns)
set_domain_ipset(line, ipset_flag) set_domain_ipset(line, ipset_flag)
end end
end end
if _node_id ~= "_direct" then if _node_id ~= "_direct" then
log(string.format(" - V2ray/Xray分流规则(%s)%s", s.remarks, fwd_dns or "默认")) log(string.format(" - V2ray/Xray分流规则(%s)%s", s.remarks, fwd_dns or "默认"))
end end
end end
end) end)
end end
--如果没有使用回国模式 --如果没有使用回国模式
if not returnhome then if not returnhome then
if fs.access("/usr/share/passwall/rules/gfwlist") then if fs.access("/usr/share/passwall/rules/gfwlist") then
local gfwlist_str = sys.exec('cat /usr/share/passwall/rules/gfwlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"') local gfwlist_str = sys.exec('cat /usr/share/passwall/rules/gfwlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"')
for line in string.gmatch(gfwlist_str, "[^\r\n]+") do for line in string.gmatch(gfwlist_str, "[^\r\n]+") do
if line ~= "" then if line ~= "" then
local ipset_flag = setflag_4 .. "gfwlist," .. setflag_6 .. "gfwlist6" local ipset_flag = setflag_4 .. "gfwlist," .. setflag_6 .. "gfwlist6"
if NO_PROXY_IPV6 == "1" then if NO_PROXY_IPV6 == "1" then
ipset_flag = setflag_4 .. "gfwlist" ipset_flag = setflag_4 .. "gfwlist"
set_domain_address(line, "::") set_domain_address(line, "::")
end end
if not only_global then if not only_global then
fwd_dns = TUN_DNS fwd_dns = TUN_DNS
if CHNROUTE_MODE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then if CHNROUTE_MODE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then
fwd_dns = nil fwd_dns = nil
end end
if REMOTE_FAKEDNS == "1" then if REMOTE_FAKEDNS == "1" then
ipset_flag = nil ipset_flag = nil
end end
set_domain_dns(line, fwd_dns) set_domain_dns(line, fwd_dns)
set_domain_ipset(line, ipset_flag) set_domain_ipset(line, ipset_flag)
end end
end end
end end
log(string.format(" - 防火墙域名表(gfwlist)%s", fwd_dns or "默认")) log(string.format(" - 防火墙域名表(gfwlist)%s", fwd_dns or "默认"))
end end
if chnlist and fs.access("/usr/share/passwall/rules/chnlist") and (CHNROUTE_MODE_DEFAULT_DNS == "remote" or (CHNROUTE_MODE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0")) then if chnlist and fs.access("/usr/share/passwall/rules/chnlist") and (CHNROUTE_MODE_DEFAULT_DNS == "remote" or (CHNROUTE_MODE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0")) then
fwd_dns = LOCAL_DNS fwd_dns = LOCAL_DNS
local chnlist_str = sys.exec('cat /usr/share/passwall/rules/chnlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"') local chnlist_str = sys.exec('cat /usr/share/passwall/rules/chnlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"')
for line in string.gmatch(chnlist_str, "[^\r\n]+") do for line in string.gmatch(chnlist_str, "[^\r\n]+") do
if line ~= "" then if line ~= "" then
if CHNROUTE_MODE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then if CHNROUTE_MODE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then
fwd_dns = nil fwd_dns = nil
end end
set_domain_dns(line, fwd_dns) set_domain_dns(line, fwd_dns)
set_domain_ipset(line, setflag_4 .. "chnroute," .. setflag_6 .. "chnroute6") set_domain_ipset(line, setflag_4 .. "chnroute," .. setflag_6 .. "chnroute6")
end end
end end
log(string.format(" - 中国域名表(chnroute)%s", fwd_dns or "默认")) log(string.format(" - 中国域名表(chnroute)%s", fwd_dns or "默认"))
end end
else else
if fs.access("/usr/share/passwall/rules/chnlist") then if fs.access("/usr/share/passwall/rules/chnlist") then
local chnlist_str = sys.exec('cat /usr/share/passwall/rules/chnlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"') local chnlist_str = sys.exec('cat /usr/share/passwall/rules/chnlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"')
for line in string.gmatch(chnlist_str, "[^\r\n]+") do for line in string.gmatch(chnlist_str, "[^\r\n]+") do
if line ~= "" then if line ~= "" then
local ipset_flag = setflag_4 .. "chnroute," .. setflag_6 .. "chnroute6" local ipset_flag = setflag_4 .. "chnroute," .. setflag_6 .. "chnroute6"
if NO_PROXY_IPV6 == "1" then if NO_PROXY_IPV6 == "1" then
ipset_flag = setflag_4 .. "chnroute" ipset_flag = setflag_4 .. "chnroute"
set_domain_address(line, "::") set_domain_address(line, "::")
end end
if not only_global then if not only_global then
set_domain_dns(line, TUN_DNS) set_domain_dns(line, TUN_DNS)
if REMOTE_FAKEDNS == "1" then if REMOTE_FAKEDNS == "1" then
ipset_flag = nil ipset_flag = nil
end end
set_domain_ipset(line, ipset_flag) set_domain_ipset(line, ipset_flag)
end end
end end
end end
log(string.format(" - 中国域名表(chnroute)%s", TUN_DNS or "默认")) log(string.format(" - 中国域名表(chnroute)%s", TUN_DNS or "默认"))
end end
end end
local address_out = io.open(CACHE_DNS_PATH .. "/000-address.conf", "a") local address_out = io.open(CACHE_DNS_PATH .. "/000-address.conf", "a")
local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a") local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a")
local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a") local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a")
local set_name = "ipset" local set_name = "ipset"
if NFTFLAG == "1" then if NFTFLAG == "1" then
set_name = "nftset" set_name = "nftset"
end end
for key, value in pairs(list1) do for key, value in pairs(list1) do
if value.address and #value.address > 0 then if value.address and #value.address > 0 then
address_out:write(string.format("address=/.%s/%s\n", key, value.address)) address_out:write(string.format("address=/.%s/%s\n", key, value.address))
end end
if value.dns and #value.dns > 0 then if value.dns and #value.dns > 0 then
for i, dns in ipairs(value.dns) do for i, dns in ipairs(value.dns) do
server_out:write(string.format("server=/.%s/%s\n", key, dns)) server_out:write(string.format("server=/.%s/%s\n", key, dns))
end end
end end
if value.ipsets and #value.ipsets > 0 then if value.ipsets and #value.ipsets > 0 then
local ipsets_str = "" local ipsets_str = ""
for i, ipset in ipairs(value.ipsets) do for i, ipset in ipairs(value.ipsets) do
ipsets_str = ipsets_str .. ipset .. "," ipsets_str = ipsets_str .. ipset .. ","
end end
ipsets_str = ipsets_str:sub(1, #ipsets_str - 1) ipsets_str = ipsets_str:sub(1, #ipsets_str - 1)
ipset_out:write(string.format("%s=/.%s/%s\n", set_name, key, ipsets_str)) ipset_out:write(string.format("%s=/.%s/%s\n", set_name, key, ipsets_str))
end end
end end
address_out:close() address_out:close()
server_out:close() server_out:close()
ipset_out:close() ipset_out:close()
local f_out = io.open(CACHE_TEXT_FILE, "a") local f_out = io.open(CACHE_TEXT_FILE, "a")
f_out:write(new_text) f_out:write(new_text)
f_out:close() f_out:close()
end end
if api.is_install("procd\\-ujail") then if api.is_install("procd\\-ujail") then
fs.copyr(CACHE_DNS_PATH, TMP_DNSMASQ_PATH) fs.copyr(CACHE_DNS_PATH, TMP_DNSMASQ_PATH)
else else
api.remove(TMP_DNSMASQ_PATH) api.remove(TMP_DNSMASQ_PATH)
fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH) fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH)
end end
if DNSMASQ_CONF_FILE ~= "nil" then if DNSMASQ_CONF_FILE ~= "nil" then
local conf_out = io.open(DNSMASQ_CONF_FILE, "a") local conf_out = io.open(DNSMASQ_CONF_FILE, "a")
conf_out:write(string.format("conf-dir=%s\n", TMP_DNSMASQ_PATH)) conf_out:write(string.format("conf-dir=%s\n", TMP_DNSMASQ_PATH))
if dnsmasq_default_dns then if dnsmasq_default_dns then
conf_out:write(string.format("server=%s\n", dnsmasq_default_dns)) conf_out:write(string.format("server=%s\n", dnsmasq_default_dns))
conf_out:write("all-servers\n") conf_out:write("all-servers\n")
conf_out:write("no-poll\n") conf_out:write("no-poll\n")
conf_out:write("no-resolv\n") conf_out:write("no-resolv\n")
conf_out:close() conf_out:close()
log(string.format(" - 以上所列以外及默认:%s", dnsmasq_default_dns)) log(string.format(" - 以上所列以外及默认:%s", dnsmasq_default_dns))
if FLAG == "default" then if FLAG == "default" then
local f_out = io.open("/tmp/etc/passwall/default_DNS", "a") local f_out = io.open("/tmp/etc/passwall/default_DNS", "a")
f_out:write(DEFAULT_DNS) f_out:write(DEFAULT_DNS)
f_out:close() f_out:close()
end end
end end
end end
log(" - PassWall必须依赖于Dnsmasq如果你自行配置了错误的DNS流程将会导致域名(直连/代理域名)分流失效!!!") log(" - PassWall必须依赖于Dnsmasq如果你自行配置了错误的DNS流程将会导致域名(直连/代理域名)分流失效!!!")

View File

@ -35,18 +35,18 @@ local geosite_api = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/
local v2ray_asset_location = ucic:get_first(name, 'global_rules', "v2ray_location_asset", "/usr/share/v2ray/") local v2ray_asset_location = ucic:get_first(name, 'global_rules', "v2ray_location_asset", "/usr/share/v2ray/")
local log = function(...) local log = function(...)
if arg1 then if arg1 then
local result = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ") local result = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
if arg1 == "log" then if arg1 == "log" then
local f, err = io.open("/tmp/log/passwall.log", "a") local f, err = io.open("/tmp/log/passwall.log", "a")
if f and err == nil then if f and err == nil then
f:write(result .. "\n") f:write(result .. "\n")
f:close() f:close()
end end
elseif arg1 == "print" then elseif arg1 == "print" then
print(result) print(result)
end end
end end
end end
-- curl -- curl