Compare commits

...

4 Commits

Author SHA1 Message Date
gitea-action
773c783a9f luci-app-passwall: sync upstream
last commit: 69a688df90
2025-05-08 02:31:21 +08:00
gitea-action
704fdbcac4 luci-app-passwall: sync upstream
last commit: 6416b681a4
2025-05-08 02:00:20 +08:00
gitea-action
a268f8508d luci-app-passwall: sync upstream
last commit: 0297722142
2025-05-08 01:30:22 +08:00
gitea-action
b913e0bc57 luci-app-passwall: sync upstream
last commit: 079691261d
2025-05-08 01:00:30 +08:00
13 changed files with 348 additions and 24 deletions

View File

@ -41,17 +41,42 @@ end
e = t:option(DummyValue, "remarks", translate("Remarks")) e = t:option(DummyValue, "remarks", translate("Remarks"))
e.width = "15%" e.width = "15%"
---- Type
e = t:option(DummyValue, "type", translate("Type")) e = t:option(DummyValue, "type", translate("Type"))
e.width = "20%"
e.rawhtml = true
e.cfgvalue = function(t, n) e.cfgvalue = function(t, n)
local v = Value.cfgvalue(t, n) local str = ""
if v then local type = m:get(n, "type") or ""
if v == "sing-box" or v == "Xray" then if type == "sing-box" or type == "Xray" then
local protocol = m:get(n, "protocol") local protocol = m:get(n, "protocol") or ""
return v .. " -> " .. protocol if protocol == "vmess" then
protocol = "VMess"
elseif protocol == "vless" then
protocol = "VLESS"
elseif protocol == "shadowsocks" then
protocol = "SS"
elseif protocol == "shadowsocksr" then
protocol = "SSR"
elseif protocol == "wireguard" then
protocol = "WG"
elseif protocol == "hysteria" then
protocol = "HY"
elseif protocol == "hysteria2" then
protocol = "HY2"
elseif protocol == "anytls" then
protocol = "AnyTLS"
else
protocol = protocol:gsub("^%l",string.upper)
local custom = m:get(n, "custom") or "0"
if custom == "1" then
protocol = translate("Custom Config")
end end
return v
end end
if type == "sing-box" then type = "Sing-Box" end
type = type .. " " .. protocol
end
str = str .. translate(type)
return str
end end
e = t:option(DummyValue, "port", translate("Port")) e = t:option(DummyValue, "port", translate("Port"))

View File

@ -20,32 +20,42 @@ end
s.fields["type"]:value(type_name, "Hysteria2") s.fields["type"]:value(type_name, "Hysteria2")
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port")) o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("obfs"), translate("Obfs Password")) o = s:option(Value, _n("obfs"), translate("Obfs Password"))
o.rewrite_option = o.option o.rewrite_option = o.option
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("auth_password"), translate("Auth Password")) o = s:option(Value, _n("auth_password"), translate("Auth Password"))
o.password = true o.password = true
o.rewrite_option = o.option o.rewrite_option = o.option
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("udp"), translate("UDP")) o = s:option(Flag, _n("udp"), translate("UDP"))
o.default = "1" o.default = "1"
o.rewrite_option = o.option o.rewrite_option = o.option
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("up_mbps"), translate("Max upload Mbps")) o = s:option(Value, _n("up_mbps"), translate("Max upload Mbps"))
o.rewrite_option = o.option o.rewrite_option = o.option
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("down_mbps"), translate("Max download Mbps")) o = s:option(Value, _n("down_mbps"), translate("Max download Mbps"))
o.rewrite_option = o.option o.rewrite_option = o.option
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("ignoreClientBandwidth"), translate("ignoreClientBandwidth")) o = s:option(Flag, _n("ignoreClientBandwidth"), translate("ignoreClientBandwidth"))
o.default = "0" o.default = "0"
o.rewrite_option = o.option o.rewrite_option = o.option
o:depends({ [_n("custom")] = false })
o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem" o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o.validate = function(self, value, t) o.validate = function(self, value, t)
if value and value ~= "" then if value and value ~= "" then
if not fs.access(value) then if not fs.access(value) then
@ -56,9 +66,11 @@ o.validate = function(self, value, t)
end end
return nil return nil
end end
o:depends({ [_n("custom")] = false })
o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key") o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key" o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o.validate = function(self, value, t) o.validate = function(self, value, t)
if value and value ~= "" then if value and value ~= "" then
if not fs.access(value) then if not fs.access(value) then
@ -69,6 +81,28 @@ o.validate = function(self, value, t)
end end
return nil return nil
end end
o:depends({ [_n("custom")] = false })
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
o.validate = function(self, value, t)
if value and api.jsonc.parse(value) then
return value
else
return nil, translate("Must be JSON text!")
end
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value))
end
o = s:option(Flag, _n("log"), translate("Log")) o = s:option(Flag, _n("log"), translate("Log"))
o.default = "1" o.default = "1"

View File

@ -28,6 +28,8 @@ local header_type_list = {
s.fields["type"]:value(type_name, "Xray") s.fields["type"]:value(type_name, "Xray")
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(ListValue, _n("protocol"), translate("Protocol")) o = s:option(ListValue, _n("protocol"), translate("Protocol"))
o:value("vmess", "Vmess") o:value("vmess", "Vmess")
o:value("vless", "VLESS") o:value("vless", "VLESS")
@ -36,9 +38,11 @@ o:value("socks", "Socks")
o:value("shadowsocks", "Shadowsocks") o:value("shadowsocks", "Shadowsocks")
o:value("trojan", "Trojan") o:value("trojan", "Trojan")
o:value("dokodemo-door", "dokodemo-door") o:value("dokodemo-door", "dokodemo-door")
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("port"), translate("Listen Port")) o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("auth"), translate("Auth")) o = s:option(Flag, _n("auth"), translate("Auth"))
o.validate = function(self, value, t) o.validate = function(self, value, t)
@ -191,6 +195,7 @@ o:depends({ [_n("tls")] = true })
o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem" o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o.validate = function(self, value, t) o.validate = function(self, value, t)
if value and value ~= "" then if value and value ~= "" then
@ -205,6 +210,7 @@ end
o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key") o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key" o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o.validate = function(self, value, t) o.validate = function(self, value, t)
if value and value ~= "" then if value and value ~= "" then
@ -341,6 +347,7 @@ o:depends({ [_n("transport")] = "grpc" })
o = s:option(Flag, _n("acceptProxyProtocol"), translate("acceptProxyProtocol"), translate("Whether to receive PROXY protocol, when this node want to be fallback or forwarded by proxy, it must be enable, otherwise it cannot be used.")) o = s:option(Flag, _n("acceptProxyProtocol"), translate("acceptProxyProtocol"), translate("Whether to receive PROXY protocol, when this node want to be fallback or forwarded by proxy, it must be enable, otherwise it cannot be used."))
o.default = "0" o.default = "0"
o:depends({ [_n("custom")] = false })
-- [[ Fallback部分 ]]-- -- [[ Fallback部分 ]]--
o = s:option(Flag, _n("fallback"), translate("Fallback")) o = s:option(Flag, _n("fallback"), translate("Fallback"))
@ -367,9 +374,11 @@ o:depends({ [_n("fallback")] = true })
o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
o.default = "0" o.default = "0"
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) o = s:option(Flag, _n("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
o.default = "0" o.default = "0"
o:depends({ [_n("custom")] = false })
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
@ -387,6 +396,7 @@ o:value("_socks", translate("Custom Socks"))
o:value("_http", translate("Custom HTTP")) o:value("_http", translate("Custom HTTP"))
o:value("_iface", translate("Custom Interface")) o:value("_iface", translate("Custom Interface"))
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:depends({ [_n("custom")] = false })
o = s:option(Value, _n("outbound_node_address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("outbound_node_address"), translate("Address (Support Domain Name)"))
o:depends({ [_n("outbound_node")] = "_socks"}) o:depends({ [_n("outbound_node")] = "_socks"})
@ -410,6 +420,27 @@ o = s:option(Value, _n("outbound_node_iface"), translate("Interface"))
o.default = "eth1" o.default = "eth1"
o:depends({ [_n("outbound_node")] = "_iface"}) o:depends({ [_n("outbound_node")] = "_iface"})
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
o.validate = function(self, value, t)
if value and api.jsonc.parse(value) then
return value
else
return nil, translate("Must be JSON text!")
end
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value))
end
o = s:option(Flag, _n("log"), translate("Log")) o = s:option(Flag, _n("log"), translate("Log"))
o.default = "1" o.default = "1"
o.rmempty = false o.rmempty = false

View File

@ -32,6 +32,8 @@ local ss_method_list = {
s.fields["type"]:value(type_name, "Sing-Box") s.fields["type"]:value(type_name, "Sing-Box")
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(ListValue, _n("protocol"), translate("Protocol")) o = s:option(ListValue, _n("protocol"), translate("Protocol"))
o:value("mixed", "Mixed") o:value("mixed", "Mixed")
o:value("socks", "Socks") o:value("socks", "Socks")
@ -54,9 +56,11 @@ if version_ge_1_12_0 then
o:value("anytls", "AnyTLS") o:value("anytls", "AnyTLS")
end end
o:value("direct", "Direct") o:value("direct", "Direct")
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("port"), translate("Listen Port")) o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("auth"), translate("Auth")) o = s:option(Flag, _n("auth"), translate("Auth"))
o.validate = function(self, value, t) o.validate = function(self, value, t)
@ -260,6 +264,7 @@ end
o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem" o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "naive" }) o:depends({ [_n("protocol")] = "naive" })
o:depends({ [_n("protocol")] = "hysteria" }) o:depends({ [_n("protocol")] = "hysteria" })
@ -278,6 +283,7 @@ end
o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key") o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key" o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "naive" }) o:depends({ [_n("protocol")] = "naive" })
o:depends({ [_n("protocol")] = "hysteria" }) o:depends({ [_n("protocol")] = "hysteria" })
@ -389,9 +395,11 @@ o:depends({ [_n("tcpbrutal")] = true })
o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
o.default = "0" o.default = "0"
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) o = s:option(Flag, _n("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
o.default = "0" o.default = "0"
o:depends({ [_n("custom")] = false })
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
@ -409,6 +417,7 @@ o:value("_socks", translate("Custom Socks"))
o:value("_http", translate("Custom HTTP")) o:value("_http", translate("Custom HTTP"))
o:value("_iface", translate("Custom Interface")) o:value("_iface", translate("Custom Interface"))
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:depends({ [_n("custom")] = false })
o = s:option(Value, _n("outbound_node_address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("outbound_node_address"), translate("Address (Support Domain Name)"))
o:depends({ [_n("outbound_node")] = "_socks" }) o:depends({ [_n("outbound_node")] = "_socks" })
@ -432,6 +441,27 @@ o = s:option(Value, _n("outbound_node_iface"), translate("Interface"))
o.default = "eth1" o.default = "eth1"
o:depends({ [_n("outbound_node")] = "_iface" }) o:depends({ [_n("outbound_node")] = "_iface" })
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
o.validate = function(self, value, t)
if value and api.jsonc.parse(value) then
return value
else
return nil, translate("Must be JSON text!")
end
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value))
end
o = s:option(Flag, _n("log"), translate("Log")) o = s:option(Flag, _n("log"), translate("Log"))
o.default = "1" o.default = "1"
o.rmempty = false o.rmempty = false

View File

@ -24,21 +24,49 @@ local ssrust_encrypt_method_list = {
s.fields["type"]:value(type_name, translate("Shadowsocks Rust")) s.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port")) o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("password"), translate("Password")) o = s:option(Value, _n("password"), translate("Password"))
o.password = true o.password = true
o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("method"), translate("Encrypt Method")) o = s:option(ListValue, _n("method"), translate("Encrypt Method"))
for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("timeout"), translate("Connection Timeout")) o = s:option(Value, _n("timeout"), translate("Connection Timeout"))
o.datatype = "uinteger" o.datatype = "uinteger"
o.default = 300 o.default = 300
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"))
o.default = "0" o.default = "0"
o:depends({ [_n("custom")] = false })
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
o.validate = function(self, value, t)
if value and api.jsonc.parse(value) then
return value
else
return nil, translate("Must be JSON text!")
end
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value))
end
o = s:option(Flag, _n("log"), translate("Log")) o = s:option(Flag, _n("log"), translate("Log"))
o.default = "1" o.default = "1"

View File

@ -27,21 +27,49 @@ local ss_encrypt_method_list = {
s.fields["type"]:value(type_name, translate("Shadowsocks")) s.fields["type"]:value(type_name, translate("Shadowsocks"))
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port")) o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("password"), translate("Password")) o = s:option(Value, _n("password"), translate("Password"))
o.password = true o.password = true
o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("method"), translate("Encrypt Method")) o = s:option(ListValue, _n("method"), translate("Encrypt Method"))
for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("timeout"), translate("Connection Timeout")) o = s:option(Value, _n("timeout"), translate("Connection Timeout"))
o.datatype = "uinteger" o.datatype = "uinteger"
o.default = 300 o.default = 300
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"))
o.default = "0" o.default = "0"
o:depends({ [_n("custom")] = false })
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
o.validate = function(self, value, t)
if value and api.jsonc.parse(value) then
return value
else
return nil, translate("Must be JSON text!")
end
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value))
end
o = s:option(Flag, _n("log"), translate("Log")) o = s:option(Flag, _n("log"), translate("Log"))
o.default = "1" o.default = "1"

View File

@ -37,31 +37,63 @@ local ssr_obfs_list = {
s.fields["type"]:value(type_name, translate("ShadowsocksR")) s.fields["type"]:value(type_name, translate("ShadowsocksR"))
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port")) o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("password"), translate("Password")) o = s:option(Value, _n("password"), translate("Password"))
o.password = true o.password = true
o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("method"), translate("Encrypt Method")) o = s:option(ListValue, _n("method"), translate("Encrypt Method"))
for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end
o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("protocol"), translate("Protocol")) o = s:option(ListValue, _n("protocol"), translate("Protocol"))
for a, t in ipairs(ssr_protocol_list) do o:value(t) end for a, t in ipairs(ssr_protocol_list) do o:value(t) end
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("protocol_param"), translate("Protocol_param")) o = s:option(Value, _n("protocol_param"), translate("Protocol_param"))
o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("obfs"), translate("Obfs")) o = s:option(ListValue, _n("obfs"), translate("Obfs"))
for a, t in ipairs(ssr_obfs_list) do o:value(t) end for a, t in ipairs(ssr_obfs_list) do o:value(t) end
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("obfs_param"), translate("Obfs_param")) o = s:option(Value, _n("obfs_param"), translate("Obfs_param"))
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("timeout"), translate("Connection Timeout")) o = s:option(Value, _n("timeout"), translate("Connection Timeout"))
o.datatype = "uinteger" o.datatype = "uinteger"
o.default = 300 o.default = 300
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"))
o.default = "0" o.default = "0"
o:depends({ [_n("custom")] = false })
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
o.validate = function(self, value, t)
if value and api.jsonc.parse(value) then
return value
else
return nil, translate("Must be JSON text!")
end
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value))
end
o = s:option(Flag, _n("udp_forward"), translate("UDP Forward")) o = s:option(Flag, _n("udp_forward"), translate("UDP Forward"))
o.default = "1" o.default = "1"

View File

@ -190,6 +190,11 @@ function base64Decode(text)
end end
end end
function base64Encode(text)
local result = nixio.bin.b64encode(text)
return result
end
--提取URL中的域名和端口(no ip) --提取URL中的域名和端口(no ip)
function get_domain_port_from_url(url) function get_domain_port_from_url(url)
local scheme, domain, port = string.match(url, "^(https?)://([%w%.%-]+):?(%d*)") local scheme, domain, port = string.match(url, "^(https?)://([%w%.%-]+):?(%d*)")
@ -1232,6 +1237,10 @@ function luci_types(id, m, s, type_name, option_prefix)
end end
s.fields[key].cfgvalue = function(self, section) s.fields[key].cfgvalue = function(self, section)
-- 添加自定义 custom_cfgvalue 属性,如果有自定义的 custom_cfgvalue 函数,则使用自定义的 cfgvalue 逻辑
if self.custom_cfgvalue then
return self:custom_cfgvalue(section)
else
if self.rewrite_option then if self.rewrite_option then
return m:get(section, self.rewrite_option) return m:get(section, self.rewrite_option)
else else
@ -1240,6 +1249,7 @@ function luci_types(id, m, s, type_name, option_prefix)
end end
end end
end end
end
s.fields[key].write = function(self, section, value) s.fields[key].write = function(self, section, value)
if s.fields["type"]:formvalue(id) == type_name then if s.fields["type"]:formvalue(id) == type_name then
-- 添加自定义 custom_write 属性,如果有自定义的 custom_write 函数,则使用自定义的 write 逻辑 -- 添加自定义 custom_write 属性,如果有自定义的 custom_write 函数,则使用自定义的 write 逻辑

View File

@ -32,12 +32,16 @@ local function cmd(cmd)
end end
local function ipt(arg) local function ipt(arg)
if ipt_bin and #ipt_bin > 0 then
cmd(ipt_bin .. " -w " .. arg) cmd(ipt_bin .. " -w " .. arg)
end end
end
local function ip6t(arg) local function ip6t(arg)
if ip6t_bin and #ip6t_bin > 0 then
cmd(ip6t_bin .. " -w " .. arg) cmd(ip6t_bin .. " -w " .. arg)
end 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
@ -129,7 +133,11 @@ local function start()
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
if user.custom == "1" and user.config_str then
config = jsonc.parse(api.base64Decode(user.config_str))
else
config = require(require_dir .. "util_shadowsocks").gen_config_server(user) config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
end
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
@ -138,23 +146,54 @@ local function start()
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
if user.custom == "1" and user.config_str then
config = jsonc.parse(api.base64Decode(user.config_str))
else
config = require(require_dir .. "util_shadowsocks").gen_config_server(user) config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
end
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 == "sing-box" then
config = require(require_dir .. "util_sing-box").gen_config_server(user)
bin = ln_run(api.get_app_path("sing-box"), "sing-box", "run -c " .. config_file, log_path)
elseif type == "Xray" then elseif type == "Xray" then
if user.custom == "1" and user.config_str then
config = jsonc.parse(api.base64Decode(user.config_str))
if log_path then
if not config.log then
config.log = {}
end
config.log.loglevel = user.loglevel
end
else
config = require(require_dir .. "util_xray").gen_config_server(user) config = require(require_dir .. "util_xray").gen_config_server(user)
end
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 == "sing-box" then
if user.custom == "1" and user.config_str then
config = jsonc.parse(api.base64Decode(user.config_str))
if log_path then
if not config.log then
config.log = {}
end
config.log.timestamp = true
config.log.disabled = false
config.log.level = user.loglevel
config.log.output = log_path
end
else
config = require(require_dir .. "util_sing-box").gen_config_server(user)
end
bin = ln_run(api.get_app_path("sing-box"), "sing-box", "run -c " .. config_file, log_path)
elseif type == "Hysteria2" then
if user.custom == "1" and user.config_str then
config = jsonc.parse(api.base64Decode(user.config_str))
else
config = require(require_dir .. "util_hysteria2").gen_config_server(user)
end
bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", 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 == "Hysteria2" then
config = require(require_dir .. "util_hysteria2").gen_config_server(user)
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
@ -163,7 +202,7 @@ local function start()
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", remarks, config_file))
end end
if bin then if bin then
@ -171,7 +210,7 @@ local function start()
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 and port 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))

View File

@ -1846,6 +1846,15 @@ msgstr "端口跳跃范围"
msgid "Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,)." msgid "Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,)."
msgstr "格式为1000:2000 或 1000-2000 多组时用逗号(,)隔开。" msgstr "格式为1000:2000 或 1000-2000 多组时用逗号(,)隔开。"
msgid "Use Custom Config"
msgstr "使用自定义配置"
msgid "Custom Config"
msgstr "自定义配置"
msgid "Must be JSON text!"
msgstr "必须是 JSON 文本内容!"
msgid "Geo View" msgid "Geo View"
msgstr "Geo 查询" msgstr "Geo 查询"

View File

@ -1704,6 +1704,8 @@ start_dns() {
ln_run "$(first_type dnsmasq)" "dnsmasq_default" "/dev/null" -C ${GLOBAL_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/dnsmasq.pid ln_run "$(first_type dnsmasq)" "dnsmasq_default" "/dev/null" -C ${GLOBAL_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/dnsmasq.pid
set_cache_var "ACL_default_dns_port" "${GLOBAL_DNSMASQ_PORT}" set_cache_var "ACL_default_dns_port" "${GLOBAL_DNSMASQ_PORT}"
DNS_REDIRECT_PORT=${GLOBAL_DNSMASQ_PORT} DNS_REDIRECT_PORT=${GLOBAL_DNSMASQ_PORT}
#dhcp.leases to hosts
$APP_PATH/lease2hosts.sh > /dev/null 2>&1 &
fi fi
} }
@ -1928,6 +1930,8 @@ acl_app() {
ln_run "$(first_type dnsmasq)" "dnsmasq_${sid}" "/dev/null" -C ${dnsmasq_conf} -x ${acl_path}/dnsmasq.pid ln_run "$(first_type dnsmasq)" "dnsmasq_${sid}" "/dev/null" -C ${dnsmasq_conf} -x ${acl_path}/dnsmasq.pid
set_cache_var "ACL_${sid}_dns_port" "${dnsmasq_port}" set_cache_var "ACL_${sid}_dns_port" "${dnsmasq_port}"
set_cache_var "node_${tcp_node}_$(echo -n "${tcp_proxy_mode}${remote_dns}" | md5sum | cut -d " " -f1)" "${dnsmasq_port}" set_cache_var "node_${tcp_node}_$(echo -n "${tcp_proxy_mode}${remote_dns}" | md5sum | cut -d " " -f1)" "${dnsmasq_port}"
#dhcp.leases to hosts
$APP_PATH/lease2hosts.sh > /dev/null 2>&1 &
} }
_redir_port=$(get_cache_var "node_${tcp_node}_redir_port") _redir_port=$(get_cache_var "node_${tcp_node}_redir_port")
_socks_port=$(get_cache_var "node_${tcp_node}_socks_port") _socks_port=$(get_cache_var "node_${tcp_node}_socks_port")
@ -2155,6 +2159,7 @@ stop() {
} }
rm -rf $TMP_PATH rm -rf $TMP_PATH
rm -rf /tmp/lock/${CONFIG}_socks_auto_switch* rm -rf /tmp/lock/${CONFIG}_socks_auto_switch*
rm -rf /tmp/lock/${CONFIG}_lease2hosts*
echolog "清空并关闭相关程序和缓存完成。" echolog "清空并关闭相关程序和缓存完成。"
exit 0 exit 0
} }

View File

@ -693,6 +693,12 @@ function add_rule(var)
api.set_cache_var("DEFAULT_DNS", DEFAULT_DNS) api.set_cache_var("DEFAULT_DNS", DEFAULT_DNS)
end end
end end
--dhcp.leases to hosts
local hosts = "/tmp/etc/" .. appname .. "_tmp/dhcp-hosts"
sys.call("touch " .. hosts)
tinsert(conf_lines, "addn-hosts=" .. hosts)
if #conf_lines > 0 then if #conf_lines > 0 then
local conf_out = io.open(DNSMASQ_CONF_FILE, "a") local conf_out = io.open(DNSMASQ_CONF_FILE, "a")
conf_out:write(table.concat(conf_lines, "\n")) conf_out:write(table.concat(conf_lines, "\n"))

View File

@ -0,0 +1,47 @@
#!/bin/sh
# dhcp.leases to hosts
CONFIG=passwall
TMP_PATH=/tmp/etc/${CONFIG}
TMP_PATH2=/tmp/etc/${CONFIG}_tmp
LOCK_FILE=/tmp/lock/${CONFIG}_lease2hosts.lock
LEASE_FILE="/tmp/dhcp.leases"
HOSTS_FILE="$TMP_PATH2/dhcp-hosts"
TMP_FILE="/tmp/dhcp-hosts.tmp"
exec 99>"$LOCK_FILE"
flock -n 99
if [ "$?" != 0 ]; then
exit 0
fi
reload_dnsmasq_pids() {
local pidfile pid
find $TMP_PATH/acl -type f -name 'dnsmasq.pid' 2>/dev/null | while read pidfile; do
if [ -s "$pidfile" ]; then
read pid < "$pidfile"
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
kill -HUP "$pid"
fi
fi
done
}
while true; do
if [ -s "$LEASE_FILE" ]; then
awk 'NF >= 4 {print $3" "$4}' "$LEASE_FILE" | sort > "$TMP_FILE"
if [ -f "$TMP_FILE" ]; then
if [ ! -f "$HOSTS_FILE" ] || [ "$(md5sum "$TMP_FILE" | awk '{print $1}')" != "$(md5sum "$HOSTS_FILE" | awk '{print $1}')" ]; then
mv "$TMP_FILE" "$HOSTS_FILE"
reload_dnsmasq_pids
else
rm -rf "$TMP_FILE"
fi
fi
fi
sleep 60
done 2>/dev/null