mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-07-27 10:31:38 +08:00
🦄 Sync 2026-04-02 23:48:06
This commit is contained in:
parent
89b55b091a
commit
133898bee4
@ -1244,6 +1244,7 @@ return view.extend({
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_transport', form.ListValue, 'transport_xhttp_mode', _('XHTTP mode'));
|
||||
so.value('auto', _('Auto'));
|
||||
so.value('stream-one', _('stream-one'));
|
||||
so.value('stream-up', _('stream-up'));
|
||||
so.value('packet-up', _('packet-up'));
|
||||
|
||||
@ -1953,7 +1953,7 @@ msgstr "混淆类型"
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:408
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:409
|
||||
msgid "Obfuscated as %s"
|
||||
msgstr "混淆为"
|
||||
msgstr "混淆为%s"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:880
|
||||
msgid "One or more numbers in the range 0-63 separated by commas"
|
||||
|
||||
@ -1953,7 +1953,7 @@ msgstr "混淆類型"
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:408
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:409
|
||||
msgid "Obfuscated as %s"
|
||||
msgstr "混淆為"
|
||||
msgstr "混淆為%s"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:880
|
||||
msgid "One or more numbers in the range 0-63 separated by commas"
|
||||
|
||||
@ -1714,7 +1714,7 @@ local current_node = map:get(section)
|
||||
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
if ((!queryParam.security || queryParam.security == "") && queryParam.sni && queryParam.sni != "") {
|
||||
if (!queryParam.security || queryParam.security == "") {
|
||||
queryParam.security = "tls";
|
||||
}
|
||||
if (queryParam.security) {
|
||||
|
||||
@ -1490,7 +1490,7 @@ local function processData(szType, content, add_mode, group)
|
||||
result.address = host_port
|
||||
end
|
||||
result.tls = "0"
|
||||
if (not params.security or params.security == "") and params.sni and params.sni ~= "" then
|
||||
if not params.security or params.security == "" then
|
||||
params.security = "tls"
|
||||
end
|
||||
if params.security == "tls" or params.security == "reality" then
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall2
|
||||
PKG_VERSION:=26.3.5
|
||||
PKG_VERSION:=26.4.2
|
||||
PKG_RELEASE:=1
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
|
||||
@ -459,17 +459,11 @@ function copy_node()
|
||||
local uuid = api.gen_short_uuid()
|
||||
uci:section(appname, "nodes", uuid)
|
||||
for k, v in pairs(uci:get_all(appname, section)) do
|
||||
local filter = k:find("%.")
|
||||
if filter and filter == 1 then
|
||||
else
|
||||
xpcall(function()
|
||||
uci:set(appname, uuid, k, v)
|
||||
end,
|
||||
function(e)
|
||||
end)
|
||||
if not k:match("^%.") and k ~= "group" then
|
||||
if k == "remarks" then v = (v or "") .. "(1)" end
|
||||
uci:set(appname, uuid, k, v)
|
||||
end
|
||||
end
|
||||
uci:delete(appname, uuid, "group")
|
||||
uci:set(appname, uuid, "add_mode", 1)
|
||||
api.uci_save(uci, appname)
|
||||
http.redirect(api.url("node_config", uuid))
|
||||
|
||||
@ -95,7 +95,7 @@ current_node = current_node_id and m.uci:get_all(appname, current_node_id) or {}
|
||||
|
||||
-- Shunt Start
|
||||
if (has_singbox or has_xray) and #nodes_table > 0 then
|
||||
if #normal_list > 0 then
|
||||
if #normal_list > 0 or #iface_list > 0 then
|
||||
if current_node.protocol == "_shunt" then
|
||||
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall2/client/include/shunt_options.lua")
|
||||
setfenv(shunt_lua, getfenv(1))(m, s, {
|
||||
@ -112,7 +112,7 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
|
||||
})
|
||||
end
|
||||
else
|
||||
local tips = s:taboption("Main", DummyValue, "tips", " ")
|
||||
local tips = s:taboption("Main", DummyValue, "tips", " ")
|
||||
tips.rawhtml = true
|
||||
tips.cfgvalue = function(t, n)
|
||||
return string.format('<a style="color: red">%s</a>', translate("There are no available nodes, please add or subscribe nodes first."))
|
||||
@ -351,6 +351,9 @@ end
|
||||
local o_node = s.fields["node"]
|
||||
local o_socks = s2.fields["node"]
|
||||
for k, v in pairs(nodes_table) do
|
||||
if #normal_list == 0 and #iface_list == 0 then
|
||||
break
|
||||
end
|
||||
o_node:value(v.id, v["remark"])
|
||||
o_node.group[#o_node.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
|
||||
o_socks:value(v.id, v["remark"])
|
||||
|
||||
@ -9,6 +9,9 @@ if not arg[1] or not m:get(arg[1]) then
|
||||
luci.http.redirect(api.url("node_list"))
|
||||
end
|
||||
|
||||
fs = require "nixio.fs"
|
||||
formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
|
||||
|
||||
local header = Template(appname .. "/node_config/header")
|
||||
header.api = api
|
||||
header.section = arg[1]
|
||||
@ -61,12 +64,18 @@ o.write = function(self, section, value)
|
||||
m:set(section, self.option, value)
|
||||
end
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
local types_dir = "/usr/lib/lua/luci/model/cbi/passwall2/client/type/"
|
||||
s.val = {}
|
||||
s.val["type"] = m.uci:get(appname, arg[1], "type")
|
||||
s.val["protocol"] = m.uci:get(appname, arg[1], "protocol")
|
||||
|
||||
if luci.http.formvalue("cbi.submit") == "1" then
|
||||
local formvalue_type = luci.http.formvalue(formvalue_key .. "type")
|
||||
if formvalue_type then
|
||||
s.val["type"] = formvalue_type
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(ListValue, "type", translate("Type"))
|
||||
|
||||
local type_table = {}
|
||||
|
||||
@ -127,9 +127,11 @@ o.validate = function(self, value)
|
||||
return value:gsub("%s+", ""):gsub("%z", "")
|
||||
end
|
||||
|
||||
o = s:option(Flag, "allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "1"
|
||||
o = s:option(Flag, "allowInsecure", translate("allowInsecure"))
|
||||
o.default = "0"
|
||||
o.rmempty = false
|
||||
o.description = translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped.") .. "<br>" ..
|
||||
translate("Used when the node link does not include this parameter.")
|
||||
|
||||
o = s:option(ListValue, "filter_keyword_mode", translate("Filter keyword Mode"))
|
||||
o.default = "5"
|
||||
|
||||
@ -168,14 +168,17 @@ if has_xray then
|
||||
o:depends("fragment", true)
|
||||
|
||||
o = s_xray:option(Value, "fragment_length", translate("Fragment Length"), translate("Fragmented packet length (byte)"))
|
||||
o.datatype = "or(uinteger,portrange)"
|
||||
o.default = "100-200"
|
||||
o:depends("fragment", true)
|
||||
|
||||
o = s_xray:option(Value, "fragment_interval", translate("Fragment Interval"), translate("Fragmentation interval (ms)"))
|
||||
o = s_xray:option(Value, "fragment_delay", translate("Fragment Delay"), translate("Fragmentation interval (ms)"))
|
||||
o.datatype = "or(uinteger,portrange)"
|
||||
o.default = "10-20"
|
||||
o:depends("fragment", true)
|
||||
|
||||
o = s_xray:option(Value, "fragment_maxSplit", translate("Max Split"), translate("Limit the maximum number of splits."))
|
||||
o.datatype = "or(uinteger,portrange)"
|
||||
o.default = "100-200"
|
||||
o:depends("fragment", true)
|
||||
|
||||
@ -225,22 +228,18 @@ if has_xray then
|
||||
|
||||
o = s_xray_noise:option(ListValue, "type", translate("Type"))
|
||||
o:value("rand", "rand")
|
||||
o:value("array", "array")
|
||||
o:value("str", "str")
|
||||
o:value("hex", "hex")
|
||||
o:value("base64", "base64")
|
||||
|
||||
o = s_xray_noise:option(Value, "packet", translate("Packet"))
|
||||
o = s_xray_noise:option(Value, "packet", translate("Packet | Rand Length"))
|
||||
o.datatype = "minlength(1)"
|
||||
o.rmempty = false
|
||||
|
||||
o = s_xray_noise:option(Value, "delay", translate("Delay (ms)"))
|
||||
o.datatype = "or(uinteger,portrange)"
|
||||
o.rmempty = false
|
||||
|
||||
o = s_xray_noise:option(ListValue, "applyTo", translate("IP Type"))
|
||||
o:value("ip", "ALL")
|
||||
o:value("ipv4", "IPv4")
|
||||
o:value("ipv6", "IPv6")
|
||||
end
|
||||
|
||||
if has_singbox then
|
||||
|
||||
@ -20,9 +20,6 @@ local function _n(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
o = s:option(ListValue, _n("protocol"), translate("Protocol"))
|
||||
o:value("udp", "UDP")
|
||||
|
||||
o = s:option(Value, _n("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, _n("port"), translate("Port"))
|
||||
@ -67,7 +64,10 @@ o.rewrite_option = o.option
|
||||
o = s:option(Value, _n("recv_window_conn"), translate("QUIC connection receive window"))
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, _n("idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s-120s)")
|
||||
o = s:option(Value, _n("idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s~120s)")
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, _n("keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Example:") .. "10s (2s~60s)")
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Flag, _n("disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||
|
||||
@ -25,7 +25,6 @@ local function _n(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
|
||||
local formvalue_proto = luci.http.formvalue(formvalue_key .. _n("protocol"))
|
||||
|
||||
if formvalue_proto then s.val["protocol"] = formvalue_proto end
|
||||
@ -326,7 +325,10 @@ o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s-120s)")
|
||||
o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s~120s)")
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Value, _n("hysteria2_keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Example:") .. "10s (2s~60s)")
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Flag, _n("hysteria2_disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||
@ -368,7 +370,7 @@ o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
-- o:value("1.3")
|
||||
-- o:depends({ [_n("tls")] = true })
|
||||
|
||||
o = s:option(Value, _n("tls_serverName"), translate("Domain"))
|
||||
o = s:option(Value, _n("tls_serverName"), "SNI " .. translate("Domain"))
|
||||
o:depends({ [_n("tls")] = true })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
@ -404,7 +406,7 @@ o.validate = function(self, value)
|
||||
end
|
||||
|
||||
o = s:option(ListValue, _n("ech_ForceQuery"), translate("ECH Query Policy"), translate("Controls the policy used when performing DNS queries for ECH configuration."))
|
||||
o.default = "none"
|
||||
o.default = "full"
|
||||
o:value("none")
|
||||
o:value("half")
|
||||
o:value("full")
|
||||
@ -687,10 +689,12 @@ o:depends({ [_n("protocol")] = "shadowsocks" })
|
||||
o:depends({ [_n("protocol")] = "wireguard" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(TextValue, _n("finalmask"), " ", translate("An FinalMaskObject in JSON format, used for sharing."))
|
||||
o = s:option(TextValue, _n("finalmask"), " ")
|
||||
o:depends({ [_n("use_finalmask")] = true })
|
||||
o.rows = 10
|
||||
o.wrap = "off"
|
||||
o.description = translate("An FinalMaskObject in JSON format, used for sharing.") .. "<br>" ..
|
||||
translate("Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related settings.")
|
||||
o.custom_cfgvalue = function(self, section, value)
|
||||
local raw = m:get(section, "finalmask")
|
||||
if raw then
|
||||
|
||||
@ -25,7 +25,6 @@ local function _n(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
|
||||
local formvalue_proto = luci.http.formvalue(formvalue_key .. _n("protocol"))
|
||||
|
||||
if formvalue_proto then s.val["protocol"] = formvalue_proto end
|
||||
@ -68,6 +67,9 @@ if singbox_tags:find("with_quic") then
|
||||
end
|
||||
o:value("anytls", "AnyTLS")
|
||||
o:value("ssh", "SSH")
|
||||
if singbox_tags:find("with_naive_outbound") then
|
||||
o:value("naive", "NaïveProxy")
|
||||
end
|
||||
o:value("_urltest", translate("URLTest"))
|
||||
o:value("_shunt", translate("Shunt"))
|
||||
o:value("_iface", translate("Custom Interface"))
|
||||
@ -227,6 +229,7 @@ o = s:option(Value, _n("username"), translate("Username"))
|
||||
o:depends({ [_n("protocol")] = "http" })
|
||||
o:depends({ [_n("protocol")] = "socks" })
|
||||
o:depends({ [_n("protocol")] = "ssh" })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(Value, _n("password"), translate("Password"))
|
||||
o.password = true
|
||||
@ -238,6 +241,7 @@ o:depends({ [_n("protocol")] = "trojan" })
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "anytls" })
|
||||
o:depends({ [_n("protocol")] = "ssh" })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(ListValue, _n("security"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(security_list) do o:value(t) end
|
||||
@ -285,6 +289,7 @@ end
|
||||
o = s:option(Flag, _n("uot"), translate("UDP over TCP"))
|
||||
o:depends({ [_n("protocol")] = "socks" })
|
||||
o:depends({ [_n("protocol")] = "shadowsocks" })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(Value, _n("alter_id"), "Alter ID")
|
||||
o.datatype = "uinteger"
|
||||
@ -345,9 +350,6 @@ if singbox_tags:find("with_quic") then
|
||||
|
||||
o = s:option(Flag, _n("hysteria_disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, _n("hysteria_alpn"), translate("QUIC TLS ALPN"))
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
@ -387,6 +389,8 @@ if singbox_tags:find("with_quic") then
|
||||
o:value("http/1.1")
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h3,h2,http/1.1")
|
||||
o:value("spdy/3.1")
|
||||
o:value("h3,spdy/3.1")
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
end
|
||||
|
||||
@ -437,6 +441,26 @@ o = s:option(Value, _n("ssh_client_version"), translate("Client Version"), trans
|
||||
o:depends({ [_n("protocol")] = "ssh" })
|
||||
-- [[ SSH config end ]] --
|
||||
|
||||
-- [[ naive start ]] --
|
||||
o = s:option(Value, _n("naive_insecure_concurrency"), translate("Concurrent Tunnels"))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "0"
|
||||
o.default = "0"
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(Flag, _n("naive_quic"), translate("QUIC"))
|
||||
o.default = 0
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(ListValue, _n("naive_congestion_control"), translate("Congestion control algorithm"))
|
||||
o.default = "bbr"
|
||||
o:value("bbr", translate("BBR"))
|
||||
o:value("bbr2", translate("BBRv2"))
|
||||
o:value("cubic", translate("CUBIC"))
|
||||
o:value("reno", translate("New Reno"))
|
||||
o:depends({ [_n("naive_quic")] = "1" })
|
||||
-- [[ naive end ]] --
|
||||
|
||||
o = s:option(Flag, _n("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o:depends({ [_n("protocol")] = "vmess" })
|
||||
@ -446,7 +470,7 @@ o:depends({ [_n("protocol")] = "trojan" })
|
||||
o:depends({ [_n("protocol")] = "shadowsocks" })
|
||||
o:depends({ [_n("protocol")] = "anytls" })
|
||||
|
||||
o = s:option(ListValue, _n("alpn"), translate("alpn"))
|
||||
o = s:option(ListValue, _n("alpn"), translate("ALPN"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("h3")
|
||||
@ -456,6 +480,7 @@ o:value("http/1.1")
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h3,h2,http/1.1")
|
||||
o:depends({ [_n("tls")] = true })
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Flag, _n("tls_disable_sni"), translate("Disable SNI"), translate("Do not send server name in ClientHello."))
|
||||
o.default = "0"
|
||||
@ -463,14 +488,13 @@ o:depends({ [_n("tls")] = true })
|
||||
o:depends({ [_n("protocol")] = "hysteria"})
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(Value, _n("tls_serverName"), translate("Domain"))
|
||||
o = s:option(Value, _n("tls_serverName"), "SNI " .. translate("Domain"))
|
||||
o:depends({ [_n("tls")] = true })
|
||||
o:depends({ [_n("protocol")] = "hysteria"})
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "shadowsocks" })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(Flag, _n("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
@ -478,7 +502,6 @@ o:depends({ [_n("tls")] = true })
|
||||
o:depends({ [_n("protocol")] = "hysteria"})
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(Flag, _n("ech"), translate("ECH"))
|
||||
o.default = "0"
|
||||
@ -486,6 +509,7 @@ o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false })
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(TextValue, _n("ech_config"), translate("ECH Config"))
|
||||
o.default = ""
|
||||
@ -501,6 +525,9 @@ o.validate = function(self, value)
|
||||
return value
|
||||
end
|
||||
|
||||
o = s:option(Value, _n("ech_query_server_name"), translate("ECH Query Domain"), translate("Overrides the domain name used for ECH HTTPS record queries."))
|
||||
o:depends({ [_n("ech")] = true })
|
||||
|
||||
if singbox_tags:find("with_utls") then
|
||||
o = s:option(Flag, _n("utls"), translate("uTLS"))
|
||||
o.default = "0"
|
||||
@ -666,6 +693,7 @@ o:depends({ [_n("tcp_guise")] = "http" })
|
||||
o:depends({ [_n("transport")] = "http" })
|
||||
o:depends({ [_n("transport")] = "ws" })
|
||||
o:depends({ [_n("transport")] = "httpupgrade" })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
-- [[ Mux ]]--
|
||||
o = s:option(Flag, _n("mux"), translate("Mux"))
|
||||
|
||||
@ -128,8 +128,18 @@ o.default = 0
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(DynamicList, _n("tls_alpn"), translate("TLS ALPN"))
|
||||
o = s:option(ListValue, _n("tls_alpn"), translate("TLS ALPN"))
|
||||
o.rmempty = true
|
||||
o.default = ""
|
||||
o:value("", translate("Default"))
|
||||
o:value("h3")
|
||||
o:value("h2")
|
||||
o:value("h3,h2")
|
||||
o:value("http/1.1")
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h3,h2,http/1.1")
|
||||
o:value("spdy/3.1")
|
||||
o:value("h3,spdy/3.1")
|
||||
o.rewrite_option = o.option
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
||||
|
||||
@ -38,6 +38,7 @@ o:value("http", "HTTP")
|
||||
o:value("socks", "Socks")
|
||||
o:value("shadowsocks", "Shadowsocks")
|
||||
o:value("trojan", "Trojan")
|
||||
o:value("hysteria2", translate("Hysteria2"))
|
||||
o:value("dokodemo-door", "dokodemo-door")
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
@ -123,6 +124,30 @@ o:value("", translate("Disable"))
|
||||
o:value("xtls-rprx-vision")
|
||||
o:depends({ [_n("protocol")] = "vless" })
|
||||
|
||||
---- [[ hysteria2 ]]
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"))
|
||||
o.default = 0
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwidth")] = false })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwidth")] = false })
|
||||
|
||||
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
|
||||
|
||||
---- [[ TLS ]]
|
||||
o = s:option(Flag, _n("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
@ -191,6 +216,7 @@ o:value("http/1.1")
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h3,h2,http/1.1")
|
||||
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Flag, _n("use_mldsa65Seed"), translate("ML-DSA-65"))
|
||||
o.default = "0"
|
||||
@ -215,6 +241,7 @@ o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolu
|
||||
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("protocol")] = "hysteria2"})
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
@ -230,6 +257,7 @@ o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path
|
||||
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("protocol")] = "hysteria2"})
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
@ -402,7 +430,10 @@ o:depends({ [_n("custom")] = false })
|
||||
--[[Fast Open]]
|
||||
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"))
|
||||
o.default = "0"
|
||||
o:depends({ [_n("custom")] = false })
|
||||
o:depends({ [_n("protocol")] = "vmess", [_n("custom")] = false })
|
||||
o:depends({ [_n("protocol")] = "vless", [_n("custom")] = false })
|
||||
o:depends({ [_n("protocol")] = "shadowsocks", [_n("custom")] = false })
|
||||
o:depends({ [_n("protocol")] = "trojan", [_n("custom")] = false })
|
||||
|
||||
-- [[ Fallback ]]--
|
||||
o = s:option(Flag, _n("fallback"), translate("Fallback"))
|
||||
|
||||
@ -123,9 +123,6 @@ if singbox_tags:find("with_quic") then
|
||||
|
||||
o = s:option(Flag, _n("hysteria_disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, _n("hysteria_alpn"), translate("QUIC TLS ALPN"))
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
@ -145,12 +142,26 @@ if singbox_tags:find("with_quic") then
|
||||
o.default = "3"
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(Value, _n("tuic_alpn"), translate("QUIC TLS ALPN"))
|
||||
o = s:option(ListValue, _n("tuic_alpn"), translate("QUIC TLS ALPN"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("h3")
|
||||
o:value("h2")
|
||||
o:value("h3,h2")
|
||||
o:value("http/1.1")
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h3,h2,http/1.1")
|
||||
o:value("spdy/3.1")
|
||||
o:value("h3,spdy/3.1")
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Commands the client to use the BBR flow control algorithm"))
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"), translate("Commands the client to use the BBR flow control algorithm"))
|
||||
o.default = 0
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
@ -167,10 +178,6 @@ if singbox_tags:find("with_quic") then
|
||||
|
||||
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
end
|
||||
|
||||
o = s:option(ListValue, _n("d_protocol"), translate("Destination protocol"))
|
||||
@ -259,6 +266,18 @@ if singbox_tags:find("with_utls") then
|
||||
o:depends({ [_n("reality")] = true })
|
||||
end
|
||||
|
||||
o = s:option(ListValue, _n("alpn"), translate("ALPN"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("h3")
|
||||
o:value("h2")
|
||||
o:value("h3,h2")
|
||||
o:value("http/1.1")
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h3,h2,http/1.1")
|
||||
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
|
||||
-- [[ TLS ]] --
|
||||
|
||||
o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
|
||||
@ -1551,3 +1551,13 @@ function get_core(field, candidates)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function cleanEmptyTables(t)
|
||||
if type(t) ~= "table" then return nil end
|
||||
for k, v in pairs(t) do
|
||||
if type(v) == "table" then
|
||||
t[k] = cleanEmptyTables(v)
|
||||
end
|
||||
end
|
||||
return next(t) and t or nil
|
||||
end
|
||||
|
||||
@ -87,14 +87,14 @@ function gen_config(var)
|
||||
quic = {
|
||||
initStreamReceiveWindow = (node.hysteria2_recv_window) and tonumber(node.hysteria2_recv_window) or nil,
|
||||
initConnReceiveWindow = (node.hysteria2_recv_window_conn) and tonumber(node.hysteria2_recv_window_conn) or nil,
|
||||
maxIdleTimeout = (function()
|
||||
local timeoutStr = tostring(node.hysteria2_idle_timeout or "")
|
||||
local timeout = tonumber(timeoutStr:match("^%d+"))
|
||||
if timeout and timeout >= 4 and timeout <= 120 then
|
||||
return tostring(timeout) .. "s"
|
||||
end
|
||||
return nil
|
||||
end)(),
|
||||
maxIdleTimeout = (function(t)
|
||||
t = tonumber(tostring(t or "30"):match("^%d+"))
|
||||
return (t and t >= 4 and t <= 120) and t .. "s" or "30s"
|
||||
end)(node.hysteria2_idle_timeout),
|
||||
keepAlivePeriod = (function(t)
|
||||
t = tonumber(tostring(t or "0"):match("^%d+"))
|
||||
return (t and t >= 2 and t <= 60) and t .. "s" or nil
|
||||
end)(node.hysteria2_keep_alive_period),
|
||||
disablePathMTUDiscovery = (node.hysteria2_disable_mtu_discovery) and true or false,
|
||||
},
|
||||
bandwidth = (node.hysteria2_up_mbps or node.hysteria2_down_mbps) and {
|
||||
|
||||
@ -7,6 +7,7 @@ local appname = api.appname
|
||||
local fs = api.fs
|
||||
local CACHE_PATH = api.CACHE_PATH
|
||||
local split = api.split
|
||||
local ech_domain = {}
|
||||
|
||||
local local_version = api.get_app_version("sing-box"):match("[^v]+")
|
||||
local version_ge_1_13_0 = api.compare_versions(local_version, ">=", "1.13.0")
|
||||
@ -159,6 +160,9 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
}
|
||||
|
||||
local tls = nil
|
||||
if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" or node.protocol == "naive" then
|
||||
node.tls = "1"
|
||||
end
|
||||
if node.tls == "1" then
|
||||
local alpn = nil
|
||||
if node.alpn and node.alpn ~= "default" then
|
||||
@ -176,10 +180,35 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
--max_version = "1.3",
|
||||
fragment = fragment,
|
||||
record_fragment = record_fragment,
|
||||
ech = (node.ech == "1") and {
|
||||
enabled = true,
|
||||
config = node.ech_config and split(node.ech_config:gsub("\\n", "\n"), "\n") or {}
|
||||
} or nil,
|
||||
ech = (node.ech == "1") and (function()
|
||||
local function get_ech_domain(s) --兼容xray "域名+DNS" 格式ech
|
||||
local domain, dns = s:match("^([^+]+)%+(.+)$")
|
||||
if not domain or not dns then return nil end
|
||||
if not (dns:match("^https?://") or dns:match("^tcp://") or dns:match("^udp://") or dns:match("^h2c://")) then
|
||||
return nil
|
||||
end
|
||||
if not domain:match("^[%w%-%.]+%.[%a]+$") then return nil end
|
||||
return domain
|
||||
end
|
||||
local ech = { enabled = true }
|
||||
local config = node.ech_config
|
||||
local qname = node.ech_query_server_name
|
||||
if config and not qname then
|
||||
qname = get_ech_domain(config)
|
||||
if not qname and not (config:match("%-+%s*BEGIN") and config:match("%-+%s*END")) then
|
||||
config = "-----BEGIN ECH CONFIGS-----\n" .. config:gsub("%s+", "") .. "\n-----END ECH CONFIGS-----"
|
||||
end
|
||||
end
|
||||
if qname then
|
||||
ech.query_server_name = qname
|
||||
ech_domain[qname] = true
|
||||
elseif config then
|
||||
ech.config = { config }
|
||||
elseif node.tls_serverName and node.tls_serverName ~= "" then
|
||||
ech_domain[node.tls_serverName] = true
|
||||
end
|
||||
return ech
|
||||
end)() or nil,
|
||||
utls = (node.utls == "1" or node.reality == "1") and {
|
||||
enabled = true,
|
||||
fingerprint = node.fingerprint or "chrome"
|
||||
@ -418,20 +447,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
recv_window_conn = tonumber(node.hysteria_recv_window_conn),
|
||||
recv_window = tonumber(node.hysteria_recv_window),
|
||||
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false,
|
||||
tls = {
|
||||
enabled = true,
|
||||
server_name = node.tls_serverName,
|
||||
insecure = (node.tls_allowInsecure == "1") and true or false,
|
||||
fragment = fragment,
|
||||
record_fragment = record_fragment,
|
||||
alpn = (node.hysteria_alpn and node.hysteria_alpn ~= "") and {
|
||||
node.hysteria_alpn
|
||||
} or nil,
|
||||
ech = (node.ech == "1") and {
|
||||
enabled = true,
|
||||
config = node.ech_config and split(node.ech_config:gsub("\\n", "\n"), "\n") or {}
|
||||
} or nil
|
||||
}
|
||||
tls = tls
|
||||
}
|
||||
end
|
||||
|
||||
@ -452,22 +468,15 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
udp_over_stream = false,
|
||||
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1") and true or false,
|
||||
heartbeat = (tonumber(node.tuic_heartbeat) or 3) .. "s",
|
||||
tls = {
|
||||
enabled = true,
|
||||
disable_sni = (node.tls_disable_sni == "1") and true or false,
|
||||
server_name = node.tls_serverName,
|
||||
insecure = (node.tls_allowInsecure == "1") and true or false,
|
||||
fragment = fragment,
|
||||
record_fragment = record_fragment,
|
||||
alpn = (node.tuic_alpn and node.tuic_alpn ~= "") and {
|
||||
node.tuic_alpn
|
||||
} or nil,
|
||||
ech = (node.ech == "1") and {
|
||||
enabled = true,
|
||||
config = node.ech_config and split(node.ech_config:gsub("\\n", "\n"), "\n") or {},
|
||||
} or nil
|
||||
}
|
||||
tls = tls
|
||||
}
|
||||
if node.tuic_alpn and node.tuic_alpn ~= "default" then
|
||||
local alpn = {}
|
||||
string.gsub(node.tuic_alpn, '[^,]+', function(w)
|
||||
table.insert(alpn, w)
|
||||
end)
|
||||
if #alpn > 0 then protocol_table.tls.alpn = alpn end
|
||||
end
|
||||
end
|
||||
|
||||
if node.protocol == "hysteria2" then
|
||||
@ -494,17 +503,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
password = node.hysteria2_obfs_password
|
||||
} or nil,
|
||||
password = node.hysteria2_auth_password or nil,
|
||||
tls = {
|
||||
enabled = true,
|
||||
server_name = node.tls_serverName,
|
||||
insecure = (node.tls_allowInsecure == "1") and true or false,
|
||||
fragment = fragment,
|
||||
record_fragment = record_fragment,
|
||||
ech = (node.ech == "1") and {
|
||||
enabled = true,
|
||||
config = node.ech_config and split(node.ech_config:gsub("\\n", "\n"), "\n") or {}
|
||||
} or nil
|
||||
}
|
||||
tls = tls
|
||||
}
|
||||
end
|
||||
|
||||
@ -530,6 +529,23 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
}
|
||||
end
|
||||
|
||||
if node.protocol == "naive" then
|
||||
protocol_table = {
|
||||
username = (node.username and node.username ~= "") and node.username or "",
|
||||
password = (node.password and node.password ~= "") and node.password or "",
|
||||
insecure_concurrency = tonumber(node.naive_insecure_concurrency or 0) > 0 and tonumber(node.naive_insecure_concurrency) or 0,
|
||||
udp_over_tcp = node.uot == "1" and {
|
||||
enabled = true,
|
||||
version = 2
|
||||
} or false,
|
||||
extra_headers = node.user_agent and {
|
||||
["User-Agent"] = node.user_agent
|
||||
} or nil,
|
||||
quic = node.naive_quic == "1" and true or false,
|
||||
quic_congestion_control = (node.naive_quic == "1" and node.naive_congestion_control) and node.naive_congestion_control or nil
|
||||
}
|
||||
end
|
||||
|
||||
if protocol_table then
|
||||
for key, value in pairs(protocol_table) do
|
||||
result[key] = value
|
||||
@ -548,6 +564,14 @@ function gen_config_server(node)
|
||||
enabled = true,
|
||||
certificate_path = node.tls_certificateFile,
|
||||
key_path = node.tls_keyFile,
|
||||
alpn = (node.alpn and node.alpn ~= "default") and (function()
|
||||
local alpn = {}
|
||||
string.gsub(node.alpn, '[^,]+', function(w)
|
||||
table.insert(alpn, w)
|
||||
end)
|
||||
if #alpn > 0 then return alpn end
|
||||
return nil
|
||||
end)() or nil
|
||||
}
|
||||
|
||||
if node.tls == "1" and node.reality == "1" then
|
||||
@ -570,7 +594,7 @@ function gen_config_server(node)
|
||||
if node.tls == "1" and node.ech == "1" then
|
||||
tls.ech = {
|
||||
enabled = true,
|
||||
key = node.ech_key and split(node.ech_key:gsub("\\n", "\n"), "\n") or {},
|
||||
key = node.ech_key and { node.ech_key } or nil
|
||||
}
|
||||
end
|
||||
|
||||
@ -751,9 +775,6 @@ function gen_config_server(node)
|
||||
end
|
||||
|
||||
if node.protocol == "hysteria" then
|
||||
tls.alpn = (node.hysteria_alpn and node.hysteria_alpn ~= "") and {
|
||||
node.hysteria_alpn
|
||||
} or nil
|
||||
protocol_table = {
|
||||
up = node.hysteria_up_mbps .. " Mbps",
|
||||
down = node.hysteria_down_mbps .. " Mbps",
|
||||
@ -776,9 +797,14 @@ function gen_config_server(node)
|
||||
end
|
||||
|
||||
if node.protocol == "tuic" then
|
||||
tls.alpn = (node.tuic_alpn and node.tuic_alpn ~= "") and {
|
||||
node.tuic_alpn
|
||||
} or nil
|
||||
tls.alpn = (node.tuic_alpn and node.tuic_alpn ~= "default") and (function()
|
||||
local alpn = {}
|
||||
string.gsub(node.tuic_alpn, '[^,]+', function(w)
|
||||
table.insert(alpn, w)
|
||||
end)
|
||||
if #alpn > 0 then return alpn end
|
||||
return nil
|
||||
end)() or nil
|
||||
protocol_table = {
|
||||
users = {
|
||||
{
|
||||
@ -789,7 +815,7 @@ function gen_config_server(node)
|
||||
},
|
||||
congestion_control = node.tuic_congestion_control or "cubic",
|
||||
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1") and true or false,
|
||||
heartbeat = node.tuic_heartbeat .. "s",
|
||||
heartbeat = (tonumber(node.tuic_heartbeat) or 3) .. "s",
|
||||
tls = tls
|
||||
}
|
||||
end
|
||||
@ -1913,15 +1939,28 @@ function gen_config(var)
|
||||
|
||||
if not dns then
|
||||
dns = {
|
||||
servers = {
|
||||
{
|
||||
type = "local",
|
||||
tag = "direct"
|
||||
}
|
||||
}
|
||||
servers = {{
|
||||
type = "local",
|
||||
tag = "direct"
|
||||
}}
|
||||
}
|
||||
end
|
||||
|
||||
if next(ech_domain) ~= nil then
|
||||
table.insert(dns.servers, {
|
||||
tag = "ech-dns",
|
||||
type = "https",
|
||||
server = "223.5.5.5"
|
||||
})
|
||||
if not dns.rules then dns.rules = {} end
|
||||
local domain = {}
|
||||
for line, _ in pairs(ech_domain) do domain[#domain+1] = line end
|
||||
table.insert(dns.rules, 1, {
|
||||
domain = domain,
|
||||
server = "ech-dns"
|
||||
})
|
||||
end
|
||||
|
||||
if COMMON.default_outbound_tag == "block" then
|
||||
route.final = nil
|
||||
table.insert(route.rules, {
|
||||
|
||||
@ -25,11 +25,18 @@ function gen_config(var)
|
||||
-- certificates = node.tuic_certificate and { node.tuic_certpath } or nil,
|
||||
udp_relay_mode = node.tuic_udp_relay_mode,
|
||||
congestion_control = node.tuic_congestion_control,
|
||||
heartbeat = node.tuic_heartbeat .. "s",
|
||||
timeout = node.tuic_timeout .. "s",
|
||||
gc_interval = node.tuic_gc_interval .. "s",
|
||||
gc_lifetime = node.tuic_gc_lifetime .. "s",
|
||||
alpn = node.tuic_tls_alpn,
|
||||
heartbeat = (tonumber(node.tuic_heartbeat) or 3) .. "s",
|
||||
timeout = (tonumber(node.tuic_timeout) or 8) .. "s",
|
||||
gc_interval = (tonumber(node.tuic_gc_interval) or 3) .. "s",
|
||||
gc_lifetime = (tonumber(node.tuic_gc_lifetime) or 15) .. "s",
|
||||
alpn = (node.tuic_tls_alpn and node.tuic_tls_alpn ~= "") and (function()
|
||||
local alpn = {}
|
||||
string.gsub(node.tuic_tls_alpn, '[^,]+', function(w)
|
||||
table.insert(alpn, w)
|
||||
end)
|
||||
if #alpn > 0 then return alpn end
|
||||
return nil
|
||||
end)() or nil,
|
||||
disable_sni = (node.tuic_disable_sni == "1"),
|
||||
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1"),
|
||||
send_window = tonumber(node.tuic_send_window),
|
||||
|
||||
@ -9,21 +9,6 @@ local CACHE_PATH = api.CACHE_PATH
|
||||
|
||||
local xray_version = api.get_app_version("xray")
|
||||
|
||||
local function get_noise_packets()
|
||||
local noises = {}
|
||||
uci:foreach(appname, "xray_noise_packets", function(n)
|
||||
local noise = (n.enabled == "1") and {
|
||||
type = n.type,
|
||||
packet = n.packet,
|
||||
delay = string.find(n.delay, "-") and n.delay or tonumber(n.delay),
|
||||
applyTo = n.applyTo
|
||||
} or nil
|
||||
table.insert(noises, noise)
|
||||
end)
|
||||
if #noises == 0 then noises = nil end
|
||||
return noises
|
||||
end
|
||||
|
||||
local function get_domain_excluded()
|
||||
local path = string.format("/usr/share/%s/domains_excluded", appname)
|
||||
local content = fs.readfile(path)
|
||||
@ -146,8 +131,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
sockopt = {
|
||||
mark = 255,
|
||||
tcpFastOpen = (node.tcp_fast_open == "1") and true or nil,
|
||||
tcpMptcp = (node.tcpMptcp == "1") and true or nil,
|
||||
dialerProxy = (fragment or noise) and "dialerproxy" or nil
|
||||
tcpMptcp = (node.tcpMptcp == "1") and true or nil
|
||||
},
|
||||
network = node.transport,
|
||||
security = node.stream_security,
|
||||
@ -169,7 +153,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
return node.tls_CertByName
|
||||
end)(),
|
||||
echConfigList = (node.ech == "1") and node.ech_config or nil,
|
||||
echForceQuery = (node.ech == "1") and (node.ech_ForceQuery or "none") or nil
|
||||
echForceQuery = (node.ech == "1") and (node.ech_ForceQuery or "full") or nil
|
||||
} or nil,
|
||||
realitySettings = (node.stream_security == "reality") and {
|
||||
serverName = node.tls_serverName,
|
||||
@ -237,58 +221,31 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
path = node.xhttp_path or "/",
|
||||
host = node.xhttp_host,
|
||||
extra = (function()
|
||||
local extra_tbl = {}
|
||||
-- Parse xhttp_extra and perform simple fault tolerance.
|
||||
local extra = {}
|
||||
if node.xhttp_extra then
|
||||
local success, parsed = pcall(jsonc.parse, api.base64Decode(node.xhttp_extra))
|
||||
if success and parsed then
|
||||
extra_tbl = parsed.extra or parsed
|
||||
for k, v in pairs(extra_tbl) do
|
||||
if (type(v) == "table" and next(v) == nil) or v == nil then
|
||||
extra_tbl[k] = nil
|
||||
end
|
||||
end
|
||||
local ok, parsed = pcall(jsonc.parse, api.base64Decode(node.xhttp_extra))
|
||||
if ok and type(parsed) == "table" then
|
||||
extra = parsed.extra or parsed
|
||||
end
|
||||
end
|
||||
-- Handling User-Agent
|
||||
if node.user_agent and node.user_agent ~= "" then
|
||||
extra_tbl.headers = extra_tbl.headers or {}
|
||||
if not extra_tbl.headers["User-Agent"] and not extra_tbl.headers["user-agent"] then
|
||||
extra_tbl.headers["User-Agent"] = node.user_agent
|
||||
extra.headers = extra.headers or {}
|
||||
if not extra.headers["User-Agent"] and not extra.headers["user-agent"] then
|
||||
extra.headers["User-Agent"] = node.user_agent
|
||||
end
|
||||
end
|
||||
-- Clean up empty headers
|
||||
if extra_tbl.headers and next(extra_tbl.headers) == nil then
|
||||
extra_tbl.headers = nil
|
||||
end
|
||||
return next(extra_tbl) ~= nil and extra_tbl or nil
|
||||
return api.cleanEmptyTables(extra)
|
||||
end)()
|
||||
} or nil,
|
||||
hysteriaSettings = (node.transport == "hysteria") and {
|
||||
version = 2,
|
||||
auth = node.hysteria2_auth_password,
|
||||
up = (node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) .. "mbps" or nil,
|
||||
down = (node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) .. "mbps" or nil,
|
||||
udphop = (node.hysteria2_hop) and {
|
||||
port = string.gsub(node.hysteria2_hop, ":", "-"),
|
||||
interval = (function()
|
||||
local v = tonumber((node.hysteria2_hop_interval or "30s"):match("^%d+"))
|
||||
return (v and v >= 5) and v or 30
|
||||
end)()
|
||||
} or nil,
|
||||
maxIdleTimeout = (function()
|
||||
local timeoutStr = tostring(node.hysteria2_idle_timeout or "")
|
||||
local timeout = tonumber(timeoutStr:match("^%d+"))
|
||||
if timeout and timeout >= 4 and timeout <= 120 then
|
||||
return timeout
|
||||
end
|
||||
return 30
|
||||
end)(),
|
||||
disablePathMTUDiscovery = (node.hysteria2_disable_mtu_discovery) and true or false
|
||||
auth = node.hysteria2_auth_password
|
||||
} or nil,
|
||||
finalmask = (function()
|
||||
local finalmask
|
||||
if node.transport == "mkcp" then
|
||||
local finalmask = {}
|
||||
local TP = node.transport
|
||||
if TP == "mkcp" then
|
||||
local map = {none = "none", srtp = "header-srtp", utp = "header-utp", ["wechat-video"] = "header-wechat",
|
||||
dtls = "header-dtls", wireguard = "header-wireguard", dns = "header-dns"}
|
||||
local udp = {}
|
||||
@ -304,36 +261,55 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
c.settings = { password = node.mkcp_seed }
|
||||
end
|
||||
udp[#udp+1] = c
|
||||
finalmask = { udp = udp }
|
||||
elseif node.transport == "hysteria" and node.hysteria2_obfs_type and node.hysteria2_obfs_type ~= "" then
|
||||
finalmask = {
|
||||
udp = {{
|
||||
finalmask.udp = udp
|
||||
elseif TP == "hysteria" then
|
||||
if node.hysteria2_obfs_type and node.hysteria2_obfs_type ~= "" then
|
||||
finalmask.udp = {{
|
||||
type = node.hysteria2_obfs_type,
|
||||
settings = node.hysteria2_obfs_password and {
|
||||
password = node.hysteria2_obfs_password
|
||||
} or nil
|
||||
}}
|
||||
end
|
||||
local up = tonumber(node.hysteria2_up_mbps) or 0
|
||||
local down = tonumber(node.hysteria2_down_mbps) or 0
|
||||
finalmask.quicParams = {
|
||||
congestion = (up <= 0 and down <= 0) and "bbr" or "brutal",
|
||||
brutalUp = up > 0 and (up .. "mbps") or nil,
|
||||
brutalDown = down > 0 and (down .. "mbps") or nil,
|
||||
udpHop = (node.hysteria2_hop) and {
|
||||
ports = string.gsub(node.hysteria2_hop, ":", "-"),
|
||||
interval = (function(v)
|
||||
v = tonumber((v or "30s"):match("^%d+"))
|
||||
return (v and v >= 5) and v or 30
|
||||
end)(node.hysteria2_hop_interval)
|
||||
} or nil,
|
||||
maxIdleTimeout = (function(t)
|
||||
t = tonumber(tostring(t or "30"):match("^%d+"))
|
||||
return (t and t >= 4 and t <= 120) and t or 30
|
||||
end)(node.hysteria2_idle_timeout),
|
||||
keepAlivePeriod = (function(t)
|
||||
t = tonumber(tostring(t or "0"):match("^%d+"))
|
||||
return (t and t >= 2 and t <= 60) and t or nil
|
||||
end)(node.hysteria2_keep_alive_period),
|
||||
disablePathMTUDiscovery = tonumber(node.hysteria2_disable_mtu_discovery) == 1
|
||||
}
|
||||
end
|
||||
if fragment and fragment_table and ({raw=1, ws=1, httpupgrade=1, grpc=1, xhttp=1})[TP] then
|
||||
finalmask.tcp = finalmask.tcp or {}
|
||||
finalmask.tcp[#finalmask.tcp+1] = api.clone(fragment_table)
|
||||
end
|
||||
if noise and noise_table and (TP == "mkcp" or (TP == "xhttp" and node.alpn == "h3")) then
|
||||
finalmask.udp = finalmask.udp or {}
|
||||
finalmask.udp[#finalmask.udp+1] = api.clone(noise_table)
|
||||
end
|
||||
if node.finalmask and node.finalmask ~= "" then
|
||||
local ok, fm = pcall(jsonc.parse, api.base64Decode(node.finalmask))
|
||||
if ok and type(fm) == "table" then
|
||||
if not finalmask or not next(finalmask) then
|
||||
finalmask = fm
|
||||
else
|
||||
if type(fm.udp) == "table" then
|
||||
finalmask.udp = finalmask.udp or {}
|
||||
for i = 1, #fm.udp do
|
||||
finalmask.udp[#finalmask.udp+1] = fm.udp[i]
|
||||
end
|
||||
end
|
||||
if type(fm.tcp) == "table" then
|
||||
finalmask.tcp = fm.tcp
|
||||
end
|
||||
end
|
||||
finalmask = fm
|
||||
end
|
||||
end
|
||||
return (finalmask and next(finalmask)) and finalmask or nil
|
||||
return api.cleanEmptyTables(finalmask)
|
||||
end)()
|
||||
} or nil,
|
||||
settings = {
|
||||
@ -475,6 +451,13 @@ function gen_config_server(node)
|
||||
clients = clients
|
||||
}
|
||||
end
|
||||
elseif node.protocol == "hysteria2" then
|
||||
settings = {
|
||||
version = 2,
|
||||
clients = node.hysteria2_auth_password and {
|
||||
{ auth = node.hysteria2_auth_password }
|
||||
}
|
||||
}
|
||||
elseif node.protocol == "dokodemo-door" then
|
||||
settings = {
|
||||
network = node.d_protocol,
|
||||
@ -552,6 +535,12 @@ function gen_config_server(node)
|
||||
end
|
||||
end
|
||||
|
||||
if node.protocol == "hysteria2" then
|
||||
node.protocol = "hysteria"
|
||||
node.transport = "hysteria"
|
||||
node.tls = "1"
|
||||
end
|
||||
|
||||
local config = {
|
||||
log = {
|
||||
loglevel = ("1" == node.log) and node.loglevel or "none"
|
||||
@ -618,8 +607,11 @@ function gen_config_server(node)
|
||||
maxUploadSize = node.xhttp_maxuploadsize,
|
||||
maxConcurrentUploads = node.xhttp_maxconcurrentuploads
|
||||
} or nil,
|
||||
hysteriaSettings = (node.transport == "hysteria") and {
|
||||
version = 2
|
||||
} or nil,
|
||||
finalmask = (function()
|
||||
local finalmask
|
||||
local finalmask = {}
|
||||
if node.transport == "mkcp" then
|
||||
local map = {none = "none", srtp = "header-srtp", utp = "header-utp", ["wechat-video"] = "header-wechat",
|
||||
dtls = "header-dtls", wireguard = "header-wireguard", dns = "header-dns"}
|
||||
@ -636,27 +628,32 @@ function gen_config_server(node)
|
||||
c.settings = { password = node.mkcp_seed }
|
||||
end
|
||||
udp[#udp+1] = c
|
||||
finalmask = { udp = udp }
|
||||
finalmask.udp = udp
|
||||
elseif node.transport == "hysteria" then
|
||||
if node.hysteria2_obfs_type and node.hysteria2_obfs_type ~= "" then
|
||||
finalmask.udp = {{
|
||||
type = node.hysteria2_obfs_type,
|
||||
settings = node.hysteria2_obfs_password and {
|
||||
password = node.hysteria2_obfs_password
|
||||
} or nil
|
||||
}}
|
||||
end
|
||||
local ignore = tonumber(node.hysteria2_ignore_client_bandwidth) == 1
|
||||
local up = (not ignore) and tonumber(node.hysteria2_up_mbps) or 0
|
||||
local down = (not ignore) and tonumber(node.hysteria2_down_mbps) or 0
|
||||
finalmask.quicParams = {
|
||||
congestion = (up <= 0 and down <= 0) and "bbr" or "brutal",
|
||||
brutalUp = up > 0 and (up .. "mbps") or nil,
|
||||
brutalDown = down > 0 and (down .. "mbps") or nil
|
||||
}
|
||||
end
|
||||
if node.finalmask and node.finalmask ~= "" then
|
||||
local ok, fm = pcall(jsonc.parse, api.base64Decode(node.finalmask))
|
||||
if ok and type(fm) == "table" then
|
||||
if not finalmask or not next(finalmask) then
|
||||
finalmask = fm
|
||||
else
|
||||
if type(fm.udp) == "table" then
|
||||
finalmask.udp = finalmask.udp or {}
|
||||
for i = 1, #fm.udp do
|
||||
finalmask.udp[#finalmask.udp+1] = fm.udp[i]
|
||||
end
|
||||
end
|
||||
if type(fm.tcp) == "table" then
|
||||
finalmask.tcp = fm.tcp
|
||||
end
|
||||
end
|
||||
finalmask = fm
|
||||
end
|
||||
end
|
||||
return (finalmask and next(finalmask)) and finalmask or nil
|
||||
return api.cleanEmptyTables(finalmask)
|
||||
end)(),
|
||||
sockopt = {
|
||||
tcpFastOpen = (node.tcp_fast_open == "1") and true or nil,
|
||||
@ -751,6 +748,38 @@ function gen_config(var)
|
||||
|
||||
local xray_settings = uci:get_all(appname, "@global_xray[0]") or {}
|
||||
|
||||
if xray_settings.fragment == "1" then
|
||||
local delay = xray_settings.fragment_delay
|
||||
fragment_table = {
|
||||
type = "fragment",
|
||||
settings = {
|
||||
packets = xray_settings.fragment_packets,
|
||||
length = xray_settings.fragment_length,
|
||||
delay = delay and (delay:find("-", 1, true) and delay or tonumber(delay)) or nil,
|
||||
maxSplit = xray_settings.fragment_maxSplit
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
if xray_settings.noise == "1" then
|
||||
local noises = {}
|
||||
uci:foreach(appname, "xray_noise_packets", function(n)
|
||||
if n.enabled == "1" then
|
||||
local noise = {
|
||||
rand = (n.type == "rand" and n.packet) and (n.packet:find("-", 1, true) and n.packet or tonumber(n.packet)) or nil,
|
||||
type = (n.type ~= "rand") and n.type or nil,
|
||||
packet = (n.type ~= "rand") and n.packet or nil,
|
||||
delay = n.delay and (n.delay:find("-", 1, true) and n.delay or tonumber(n.delay)) or nil
|
||||
}
|
||||
table.insert(noises, noise)
|
||||
end
|
||||
end)
|
||||
noise_table = #noises > 0 and {
|
||||
type = "noise",
|
||||
settings = { reset = 0, noise = noises }
|
||||
} or nil
|
||||
end
|
||||
|
||||
local node = node_id and uci:get_all(appname, node_id) or nil
|
||||
local balancers = {}
|
||||
local rules = {}
|
||||
@ -909,7 +938,7 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
if is_new_blc_node then
|
||||
local outboundTag = gen_outbound_get_tag(flag, blc_node_id, blc_node_tag, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.record_fragment == "1" or nil, run_socks_instance = not no_run })
|
||||
local outboundTag = gen_outbound_get_tag(flag, blc_node_id, blc_node_tag, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.noise == "1" or nil, run_socks_instance = not no_run })
|
||||
if outboundTag then
|
||||
valid_nodes[#valid_nodes + 1] = outboundTag
|
||||
end
|
||||
@ -934,7 +963,7 @@ function gen_config(var)
|
||||
local fallback_node = get_node_by_id(fallback_node_id)
|
||||
if fallback_node then
|
||||
if fallback_node.protocol ~= "_balancing" then
|
||||
local outboundTag = gen_outbound_get_tag(flag, fallback_node, fallback_node_id, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.record_fragment == "1" or nil, run_socks_instance = not no_run })
|
||||
local outboundTag = gen_outbound_get_tag(flag, fallback_node, fallback_node_id, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.noise == "1" or nil, run_socks_instance = not no_run })
|
||||
if outboundTag then
|
||||
fallback_node_tag = outboundTag
|
||||
end
|
||||
@ -964,27 +993,29 @@ function gen_config(var)
|
||||
strategy = strategy
|
||||
})
|
||||
if _node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag then
|
||||
local t = api.format_go_time(_node.probeInterval)
|
||||
if t == "0s" then
|
||||
t = "60s"
|
||||
elseif not t:find("[hm]") and tonumber(t:match("%d+")) < 10 then
|
||||
t = "10s"
|
||||
end
|
||||
if _node.balancingStrategy == "leastLoad" then
|
||||
if not burstObservatory then
|
||||
burstObservatory = {
|
||||
subjectSelector = { "blc-" },
|
||||
pingConfig = {
|
||||
destination = _node.useCustomProbeUrl and _node.probeUrl or nil,
|
||||
interval = (api.format_go_time(_node.probeInterval) ~= "0s") and api.format_go_time(_node.probeInterval) or "1m",
|
||||
sampling = 3,
|
||||
timeout = "5s"
|
||||
}
|
||||
burstObservatory = burstObservatory or {
|
||||
subjectSelector = { "blc-" },
|
||||
pingConfig = {
|
||||
destination = _node.useCustomProbeUrl and _node.probeUrl or nil,
|
||||
interval = t,
|
||||
sampling = 3,
|
||||
timeout = "5s"
|
||||
}
|
||||
end
|
||||
}
|
||||
else
|
||||
if not observatory then
|
||||
observatory = {
|
||||
subjectSelector = { "blc-" },
|
||||
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
|
||||
probeInterval = (api.format_go_time(_node.probeInterval) ~= "0s") and api.format_go_time(_node.probeInterval) or "1m",
|
||||
enableConcurrency = true
|
||||
}
|
||||
end
|
||||
observatory = observatory or {
|
||||
subjectSelector = { "blc-" },
|
||||
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
|
||||
probeInterval = t,
|
||||
enableConcurrency = true
|
||||
}
|
||||
end
|
||||
end
|
||||
local loopback_outbound = gen_loopback(loopback_tag, loopback_dst)
|
||||
@ -1731,28 +1762,6 @@ function gen_config(var)
|
||||
}
|
||||
}
|
||||
|
||||
if xray_settings.fragment == "1" or xray_settings.noise == "1" then
|
||||
table.insert(outbounds, {
|
||||
protocol = "freedom",
|
||||
tag = "dialerproxy",
|
||||
settings = {
|
||||
domainStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP",
|
||||
fragment = (xray_settings.fragment == "1") and {
|
||||
packets = (xray_settings.fragment_packets and xray_settings.fragment_packets ~= "") and xray_settings.fragment_packets,
|
||||
length = (xray_settings.fragment_length and xray_settings.fragment_length ~= "") and xray_settings.fragment_length,
|
||||
interval = (xray_settings.fragment_interval and xray_settings.fragment_interval ~= "") and xray_settings.fragment_interval,
|
||||
maxSplit = (xray_settings.fragment_maxSplit and xray_settings.fragment_maxSplit ~= "") and xray_settings.fragment_maxSplit
|
||||
} or nil,
|
||||
noises = (xray_settings.noise == "1") and get_noise_packets() or nil
|
||||
},
|
||||
streamSettings = {
|
||||
sockopt = {
|
||||
mark = 255
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
local direct_outbound = {
|
||||
protocol = "freedom",
|
||||
tag = "direct",
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
local api = self.api
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
let node_id = "<%=self.section%>";
|
||||
let url = '<%=api.url("node_config")%>/' + node_id;
|
||||
//<![CDATA[
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
waitForElement('select[name*="<%=api.appname%>"][name*="type"]', function(el) {
|
||||
@ -13,8 +11,12 @@ local api = self.api
|
||||
if (o_val != el.value) {
|
||||
let save = true;
|
||||
if (save) {
|
||||
//document.getElementsByClassName('cbi-button-save')[0].click();
|
||||
update_node({
|
||||
type: getOption("type").value
|
||||
remarks: getOption("remarks").value,
|
||||
group: getOption("group").value,
|
||||
type: getOption("type").value,
|
||||
protocol: ''
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -29,11 +31,14 @@ local api = self.api
|
||||
let name = name_split[name_split.length - 1];
|
||||
let save = true;
|
||||
if (save) {
|
||||
//document.getElementsByClassName('cbi-button-save')[0].click();
|
||||
update_node({
|
||||
remarks: getOption("remarks").value,
|
||||
group: getOption("group").value,
|
||||
protocol: getOption(name).value
|
||||
});
|
||||
} else {
|
||||
window.location.href = url + "?select_proto=" + el.value;
|
||||
window.location.href = node_config_url + "?select_proto=" + el.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -3,6 +3,9 @@ local api = self.api
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
let node_id = "<%=self.section%>";
|
||||
let node_config_url = '<%=api.url("node_config")%>/' + node_id;
|
||||
|
||||
function waitForElement(selector, callback) {
|
||||
const el = document.querySelector(selector);
|
||||
if (el) return callback(el);
|
||||
@ -18,7 +21,7 @@ local api = self.api
|
||||
|
||||
function getOption(opt) {
|
||||
var obj;
|
||||
var id = 'cbid.<%=api.appname%>.<%=self.section%>.' + opt;
|
||||
var id = 'cbid.<%=api.appname%>.' + node_id + '.' + opt;
|
||||
obj = document.getElementsByName(id)[0] || document.getElementById(id);
|
||||
if (obj) {
|
||||
var combobox = document.getElementById('cbi.combobox.' + id);
|
||||
@ -37,12 +40,12 @@ local api = self.api
|
||||
|
||||
function update_node(data) {
|
||||
XHR.get('<%=api.url("update_node")%>', {
|
||||
id: "<%=self.section%>",
|
||||
id: node_id,
|
||||
data: JSON.stringify(data)
|
||||
},
|
||||
function(x, data) {
|
||||
if (x && x.status == 200 && data.code == 1) {
|
||||
window.location.reload();
|
||||
window.location.href = node_config_url;
|
||||
}
|
||||
else {
|
||||
alert("<%:Error%>");
|
||||
|
||||
@ -675,6 +675,31 @@ local current_node = map:get(section)
|
||||
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
|
||||
}
|
||||
|
||||
params += "#" + encodeURI(v_alias.value);
|
||||
if (params[0] == "&") {
|
||||
params = params.substring(1);
|
||||
}
|
||||
url += params;
|
||||
} else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "naive") {
|
||||
protocol = "naive+https";
|
||||
var v_username = opt.get(dom_prefix + "username");
|
||||
var v_password = opt.get(dom_prefix + "password");
|
||||
var v_port = opt.get(dom_prefix + "port");
|
||||
url = encodeURIComponent(v_username.value) +
|
||||
":" + encodeURIComponent(v_password.value) +
|
||||
"@" + _address +
|
||||
":" + v_port.value + "?";
|
||||
|
||||
var params = "security=tls";
|
||||
params += opt.query("sni", dom_prefix + "tls_serverName");
|
||||
params += opt.query("insecure-concurrency", dom_prefix + "naive_insecure_concurrency");
|
||||
params += opt.query("ech", dom_prefix + "ech_config");
|
||||
params += opt.query("uot", dom_prefix + "uot");
|
||||
if (opt.get(dom_prefix + "naive_quic")?.checked) {
|
||||
protocol = "naive+quic";
|
||||
params += opt.query("congestion_control", dom_prefix + "naive_congestion_control");
|
||||
}
|
||||
|
||||
params += "#" + encodeURI(v_alias.value);
|
||||
if (params[0] == "&") {
|
||||
params = params.substring(1);
|
||||
@ -1034,10 +1059,10 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'reality', false);
|
||||
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', true);
|
||||
if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', false);
|
||||
}
|
||||
opt.set(
|
||||
dom_prefix + 'tls_allowInsecure',
|
||||
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.allowInsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0')
|
||||
);
|
||||
if (queryParam.fp && queryParam.fp.trim() != "") {
|
||||
opt.set(dom_prefix + 'utls', true);
|
||||
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
|
||||
@ -1205,7 +1230,7 @@ local current_node = map:get(section)
|
||||
var params;
|
||||
for (var i = 0; i < queryArray.length; i++) {
|
||||
params = queryArray[i].split('=');
|
||||
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
|
||||
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
opt.set(dom_prefix + 'mux', queryParam.mux === '1');
|
||||
@ -1281,21 +1306,15 @@ local current_node = map:get(section)
|
||||
queryParam.security = queryParam.security || "tls";
|
||||
opt.set(dom_prefix + 'tls', queryParam.security === "tls");
|
||||
if (queryParam.security === "tls") {
|
||||
var tls_serverName = queryParam.peer;
|
||||
if (queryParam.sni) {
|
||||
tls_serverName = queryParam.sni
|
||||
}
|
||||
tls_serverName = tls_serverName || "";
|
||||
opt.set(dom_prefix + 'tls_serverName', tls_serverName);
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.peer || queryParam.sni || "");
|
||||
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tls_CertSha', queryParam.pcs || '');
|
||||
opt.set(dom_prefix + 'tls_CertByName', queryParam.vcn || '');
|
||||
}
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', true);
|
||||
if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', false);
|
||||
}
|
||||
|
||||
opt.set(
|
||||
dom_prefix + 'tls_allowInsecure',
|
||||
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.allowInsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0')
|
||||
);
|
||||
opt.set(dom_prefix + 'tcp_fast_open', queryParam.tfo);
|
||||
opt.set(dom_prefix + 'use_finalmask', !!queryParam.fm);
|
||||
opt.set(dom_prefix + 'finalmask', queryParam.fm || "");
|
||||
@ -1327,11 +1346,11 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'uuid', ssm.id);
|
||||
opt.set(dom_prefix + 'tls', ssm.tls === "tls");
|
||||
if (ssm.tls === "tls") {
|
||||
var tls_serverName = ssm.host;
|
||||
if (ssm.sni) {
|
||||
tls_serverName = ssm.sni
|
||||
}
|
||||
opt.set(dom_prefix + 'tls_serverName', tls_serverName);
|
||||
opt.set(dom_prefix + 'tls_serverName', ssm.sni || ssm.host);
|
||||
opt.set(
|
||||
dom_prefix + 'tls_allowInsecure',
|
||||
!((ssm.allowinsecure ?? '0') === '0' && (ssm.allowInsecure ?? '0') === '0' && (ssm.insecure ?? '0') === '0')
|
||||
);
|
||||
}
|
||||
ssm.net = ssm.net.toLowerCase();
|
||||
if (ssm.net === "kcp" || ssm.net === "mkcp")
|
||||
@ -1443,10 +1462,10 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'reality', false);
|
||||
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', true);
|
||||
if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', false);
|
||||
}
|
||||
opt.set(
|
||||
dom_prefix + 'tls_allowInsecure',
|
||||
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.allowInsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0')
|
||||
);
|
||||
if (queryParam.fp && queryParam.fp.trim() != "") {
|
||||
opt.set(dom_prefix + 'utls', true);
|
||||
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
|
||||
@ -1604,9 +1623,10 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'port', m.port || "443");
|
||||
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || "");
|
||||
if (queryParam.insecure && queryParam.insecure == "1") {
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', true);
|
||||
}
|
||||
opt.set(
|
||||
dom_prefix + 'tls_allowInsecure',
|
||||
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.allowInsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0')
|
||||
);
|
||||
opt.set(dom_prefix + 'tls_CertSha', queryParam.pcs || '');
|
||||
opt.set(dom_prefix + 'tls_CertByName', queryParam.vcn || '');
|
||||
if (m.hash) {
|
||||
@ -1646,7 +1666,7 @@ local current_node = map:get(section)
|
||||
var params;
|
||||
for (i = 0; i < queryArray.length; i++) {
|
||||
params = queryArray[i].split('=');
|
||||
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
|
||||
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
opt.set(dom_prefix + 'tuic_congestion_control', queryParam.congestion_control || 'cubic');
|
||||
@ -1654,10 +1674,10 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'tuic_alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
||||
opt.set(dom_prefix + 'tls_disable_sni', queryParam.disable_sni === "1");
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', true);
|
||||
if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', false);
|
||||
}
|
||||
opt.set(
|
||||
dom_prefix + 'tls_allowInsecure',
|
||||
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0' && (queryParam.allow_insecure ?? '0') === '0')
|
||||
);
|
||||
if (hash) {
|
||||
opt.set('remarks', decodeURIComponent(hash.substr(1)));
|
||||
}
|
||||
@ -1685,10 +1705,10 @@ local current_node = map:get(section)
|
||||
var params;
|
||||
for (i = 0; i < queryArray.length; i++) {
|
||||
params = queryArray[i].split('=');
|
||||
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
|
||||
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
if ((!queryParam.security || queryParam.security == "") && queryParam.sni && queryParam.sni != "") {
|
||||
if (!queryParam.security || queryParam.security == "") {
|
||||
queryParam.security = "tls";
|
||||
}
|
||||
if (queryParam.security) {
|
||||
@ -1697,10 +1717,7 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'reality', false);
|
||||
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', true);
|
||||
if ((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0') {
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', false);
|
||||
}
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', !((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0'));
|
||||
if (queryParam.fp && queryParam.fp.trim() != "") {
|
||||
opt.set(dom_prefix + 'utls', true);
|
||||
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
|
||||
@ -1723,6 +1740,55 @@ local current_node = map:get(section)
|
||||
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (ssu[0] === "naive+https" || ssu[0] === "naive+quic") {
|
||||
if (has_singbox) {
|
||||
dom_prefix = "singbox_"
|
||||
opt.set('type', "sing-box");
|
||||
}
|
||||
opt.set(dom_prefix + 'protocol', "naive");
|
||||
var _parsedUrl = new URL("http://" + ssu[1]);
|
||||
var username = _parsedUrl.username;
|
||||
var password = _parsedUrl.password;
|
||||
var hostname = _parsedUrl.hostname;
|
||||
var port = _parsedUrl.port;
|
||||
var search = _parsedUrl.search;
|
||||
var hash = _parsedUrl.hash;
|
||||
if (!username || !password) { //某些链接会把username和password之间的:进行编码
|
||||
const decoded = decodeURIComponent(username || password || "");
|
||||
const i = decoded.indexOf(":");
|
||||
if (i > -1) {
|
||||
username = decoded.slice(0, i);
|
||||
password = decoded.slice(i + 1);
|
||||
}
|
||||
}
|
||||
opt.set(dom_prefix + 'username', decodeURIComponent(username));
|
||||
opt.set(dom_prefix + 'password', decodeURIComponent(password));
|
||||
opt.set(dom_prefix + 'address', unbracketIP(hostname));
|
||||
opt.set(dom_prefix + 'port', port || "443");
|
||||
var queryParam = {};
|
||||
if (search.length > 1) {
|
||||
var query = search.split('?')
|
||||
var queryParams = query[1];
|
||||
var queryArray = queryParams.split('&');
|
||||
var params;
|
||||
for (i = 0; i < queryArray.length; i++) {
|
||||
params = queryArray[i].split('=');
|
||||
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
opt.set(dom_prefix + 'naive_insecure_concurrency', queryParam['insecure-concurrency'] || '0');
|
||||
opt.set(dom_prefix + 'uot', (queryParam.uot ?? '0') === '1');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
||||
opt.set(dom_prefix + 'ech', !!queryParam.ech);
|
||||
opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
|
||||
if (ssu[0] === "naive+quic") {
|
||||
opt.set(dom_prefix + 'naive_quic', true);
|
||||
opt.set(dom_prefix + 'naive_congestion_control', queryParam.congestion_control || 'bbr');
|
||||
}
|
||||
if (hash) {
|
||||
opt.set('remarks', decodeURIComponent(hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (dom_prefix && dom_prefix != null) {
|
||||
if (opt.get(dom_prefix + 'port').value) {
|
||||
opt.get(dom_prefix + 'port').focus();
|
||||
|
||||
@ -5,6 +5,10 @@ local api = require "luci.passwall2.api"
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function ajax_add_node(link, group) {
|
||||
const dom = document.getElementById('modal-mask');
|
||||
dom.style.display = 'block';
|
||||
dom.innerHTML = '<div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;"><%:Processing, please wait…%></div>';
|
||||
|
||||
const chunkSize = 1000; // Fragmented sending to overcome uhttpd's limitations, with each fragment containing 1000 characters.
|
||||
const totalChunks = Math.ceil(link.length / chunkSize);
|
||||
let currentChunk = 0;
|
||||
@ -19,11 +23,15 @@ local api = require "luci.passwall2.api"
|
||||
currentChunk++;
|
||||
sendNextChunk();
|
||||
} else {
|
||||
dom.innerHTML = '';
|
||||
dom.style.display = 'none';
|
||||
alert("<%:Error%>");
|
||||
return;
|
||||
}
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
dom.innerHTML = '';
|
||||
dom.style.display = 'none';
|
||||
alert("<%:Network Error%>");
|
||||
return;
|
||||
};
|
||||
@ -40,6 +48,22 @@ local api = require "luci.passwall2.api"
|
||||
sendNextChunk();
|
||||
}
|
||||
|
||||
function decodeIfBase64(str) {
|
||||
try {
|
||||
let s = str.replace(/-/g, '+').replace(/_/g, '/');
|
||||
while (s.length % 4) s += '=';
|
||||
const decoded = decodeURIComponent(
|
||||
atob(s).split('').map(c =>
|
||||
'%' + c.charCodeAt(0).toString(16).padStart(2, '0')
|
||||
).join('')
|
||||
);
|
||||
if (btoa(unescape(encodeURIComponent(decoded))).replace(/=+$/, '') === s.replace(/=+$/, '')) {
|
||||
return decoded;
|
||||
}
|
||||
} catch (e) {}
|
||||
return str;
|
||||
}
|
||||
|
||||
function getBg(el) {
|
||||
if (!el) return null;
|
||||
const style = getComputedStyle(el);
|
||||
@ -74,15 +98,15 @@ local api = require "luci.passwall2.api"
|
||||
const group = (document.querySelector('#addlink_group_custom input[type="hidden"]')?.value || "default");
|
||||
nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").replace(/<[^>]*>/g, '').trim();
|
||||
if (nodes_link != "") {
|
||||
nodes_link = decodeIfBase64(nodes_link);
|
||||
let s = nodes_link.split('://');
|
||||
if (s.length > 1) {
|
||||
close_add_link_div();
|
||||
ajax_add_node(nodes_link, group);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
alert("<%:Please enter the correct link.%>");
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
document.getElementById("nodes_link").focus();
|
||||
}
|
||||
}
|
||||
@ -93,8 +117,7 @@ local api = require "luci.passwall2.api"
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
window.location.href = '<%=api.url("node_list")%>';
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
@ -154,8 +177,7 @@ local api = require "luci.passwall2.api"
|
||||
function(x, data) {
|
||||
if (x && x.status == 200) {
|
||||
window.location.href = '<%=api.url("node_list")%>';
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
|
||||
@ -48,8 +48,11 @@ table td, .table .td {
|
||||
background: #5e72e445 !important;
|
||||
}
|
||||
|
||||
.ping a:hover{
|
||||
text-decoration : underline;
|
||||
.ping a,
|
||||
.ping_value a,
|
||||
.tcping_value a {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
@ -413,11 +416,16 @@ table td, .table .td {
|
||||
}
|
||||
}
|
||||
if (ids.length > 0) {
|
||||
if (confirm('<%:Are you sure to delete select nodes?%>') == true){
|
||||
const dom = document.getElementById('modal-mask');
|
||||
if (confirm('<%:Are you sure to delete select nodes?%>') == true) {
|
||||
dom.style.display = 'block';
|
||||
dom.innerHTML = '<div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;"><%:Processing, please wait…%></div>';
|
||||
XHR.get('<%=api.url("delete_select_nodes")%>', {
|
||||
ids: ids.join()
|
||||
},
|
||||
function(x, data) {
|
||||
dom.innerHTML = '';
|
||||
dom.style.display = 'none';
|
||||
if (x && x.status == 200) {
|
||||
/*
|
||||
for (var i = 0 ; i < ids.length; i++) {
|
||||
@ -427,8 +435,7 @@ table td, .table .td {
|
||||
*/
|
||||
ajaxAbortAll();
|
||||
window.location.href = '<%=api.url("node_list")%>';
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
@ -553,11 +560,10 @@ table td, .table .td {
|
||||
text = "<%:Timeout%>";
|
||||
} else {
|
||||
let use_time = parseInt(result.use_time);
|
||||
if (use_time < 1000) {
|
||||
if (use_time < 1000)
|
||||
color = "green";
|
||||
} else if (use_time < 2000) {
|
||||
else if (use_time < 2000)
|
||||
color = "#fb9a05";
|
||||
}
|
||||
text = use_time + " ms";
|
||||
}
|
||||
}
|
||||
@ -569,9 +575,11 @@ table td, .table .td {
|
||||
}
|
||||
|
||||
function ping_node(cbi_id, dom, type) {
|
||||
var full = get_address_full(cbi_id);
|
||||
if (dom.dataset.busy == "1" || !cbi_id) return;
|
||||
const full = get_address_full(cbi_id);
|
||||
if ((type == "icmp" && full.address != "" ) || (type == "tcping" && full.address != "" && full.port != "")) {
|
||||
dom.onclick = null
|
||||
dom.dataset.busy = "1";
|
||||
dom.style.color = "";
|
||||
dom.innerText = "<%:Check...%>";
|
||||
XHR.get('<%=api.url("ping_node")%>', {
|
||||
address: full.address,
|
||||
@ -579,19 +587,23 @@ table td, .table .td {
|
||||
type: type
|
||||
},
|
||||
function(x, result) {
|
||||
let color = "red";
|
||||
let text = "<%:Error%>";
|
||||
if(x && x.status == 200) {
|
||||
if (result.ping == null || result.ping.trim() == "") {
|
||||
dom.outerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
text = "<%:Timeout%>";
|
||||
} else {
|
||||
var ping = parseInt(result.ping);
|
||||
if (ping < 100)
|
||||
dom.outerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||
color = "green";
|
||||
else if (ping < 200)
|
||||
dom.outerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping >= 200)
|
||||
dom.outerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
||||
color = "#fb9a05";
|
||||
text = result.ping + " ms";
|
||||
}
|
||||
}
|
||||
dom.innerText = text;
|
||||
dom.style.color = color;
|
||||
dom.dataset.busy = "0";
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -601,15 +613,15 @@ table td, .table .td {
|
||||
function pingAllNodes() {
|
||||
if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
|
||||
const now = Date.now();
|
||||
var nodes = [];
|
||||
const nodes = [];
|
||||
const ping_value = document.getElementsByClassName(auto_detection_time == "tcping" ? 'tcping_value' : 'ping_value');
|
||||
for (var i = 0; i < ping_value.length; i++) {
|
||||
var cbi_id = ping_value[i].getAttribute("cbiid");
|
||||
var full = get_address_full(cbi_id);
|
||||
for (let i = 0; i < ping_value.length; i++) {
|
||||
const cbi_id = ping_value[i].getAttribute("cbiid");
|
||||
const full = get_address_full(cbi_id);
|
||||
if ((auto_detection_time == "icmp" && full.address != "" ) || (auto_detection_time == "tcping" && full.address != "" && full.port != "")) {
|
||||
var flag = false;
|
||||
let flag = false;
|
||||
// Merge duplicates
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
for (let j = 0; j < nodes.length; j++) {
|
||||
if (nodes[j].address == full.address && nodes[j].port == full.port) {
|
||||
nodes[j].indexs = nodes[j].indexs + "," + i;
|
||||
flag = true;
|
||||
@ -621,12 +633,17 @@ table td, .table .td {
|
||||
|
||||
const cacheData = JSON.parse(localStorage.getItem(auto_detection_time + ":" + full.address + ":" + full.port));
|
||||
if (cacheData && cacheData.savetime && (now - cacheData.timestamp) < cacheData.savetime) {
|
||||
const a = ping_value[i].firstElementChild;
|
||||
let color = "red";
|
||||
if (cacheData.value < 100)
|
||||
ping_value[i].innerHTML = "<font style='color:green'>" + cacheData.value + " ms" + "</font>";
|
||||
color = "green";
|
||||
else if (cacheData.value < 200)
|
||||
ping_value[i].innerHTML = "<font style='color:#fb9a05'>" + cacheData.value + " ms" + "</font>";
|
||||
else if (cacheData.value >= 200)
|
||||
ping_value[i].innerHTML = "<font style='color:red'>" + cacheData.value + " ms" + "</font>";
|
||||
color = "#fb9a05";
|
||||
a.innerText = cacheData.value + " ms";
|
||||
a.style.color = color;
|
||||
a.onclick = function () {
|
||||
ping_node(cbi_id, this, auto_detection_time);
|
||||
};
|
||||
} else {
|
||||
localStorage.removeItem(auto_detection_time + ":" + full.address + ":" + full.port);
|
||||
nodes.push({
|
||||
@ -650,12 +667,14 @@ table td, .table .td {
|
||||
},
|
||||
function(x, result) {
|
||||
if (x && x.status == 200) {
|
||||
var strs = dom.indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
if (result.ping == null || result.ping.trim() == "") {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
} else {
|
||||
var ping = parseInt(result.ping);
|
||||
let strs = dom.indexs.split(",");
|
||||
for (let i = 0; i < strs.length; i++) {
|
||||
const a = ping_value[strs[i]].firstElementChild;
|
||||
const cbi_id = ping_value[strs[i]].getAttribute("cbiid");
|
||||
let color = "red";
|
||||
let text = "<%:Timeout%>";
|
||||
if (result.ping !== null && result.ping.trim() !== "") {
|
||||
let ping = parseInt(result.ping);
|
||||
//save to cache
|
||||
const cache_data = {
|
||||
dom_id: strs[i],
|
||||
@ -663,23 +682,33 @@ table td, .table .td {
|
||||
savetime: 60 * 1000,
|
||||
value: ping
|
||||
};
|
||||
text = result.ping + " ms";
|
||||
localStorage.setItem(auto_detection_time + ":" + dom.address + ":" + dom.port, JSON.stringify(cache_data));
|
||||
if (ping < 100)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||
color = "green";
|
||||
else if (ping < 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping >= 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
||||
color = "#fb9a05";
|
||||
}
|
||||
a.innerText = text;
|
||||
a.style.color = color;
|
||||
a.onclick = function () {
|
||||
ping_node(cbi_id, this, auto_detection_time);
|
||||
};
|
||||
}
|
||||
}
|
||||
res();
|
||||
},
|
||||
5000,
|
||||
function(x) {
|
||||
var strs = dom.indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
let strs = dom.indexs.split(",");
|
||||
for (let i = 0; i < strs.length; i++) {
|
||||
const a = ping_value[strs[i]].firstElementChild;
|
||||
const cbi_id = ping_value[strs[i]].getAttribute("cbiid");
|
||||
a.innerText = "<%:Timeout%>";
|
||||
a.style.color = "red";
|
||||
a.onclick = function () {
|
||||
ping_node(cbi_id, this, auto_detection_time);
|
||||
};
|
||||
}
|
||||
res();
|
||||
}
|
||||
@ -927,12 +956,12 @@ table td, .table .td {
|
||||
if (auto_detection_time != "icmp" && o["address"] && o["port"]) {
|
||||
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'{{id}}\', this, \'icmp\')"><%:Test%></a></span>');
|
||||
} else {
|
||||
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping_value" cbiid="{{id}}">---</span>');
|
||||
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
|
||||
}
|
||||
if (auto_detection_time != "tcping" && o["address"] && o["port"]) {
|
||||
innerHTML = innerHTML.split("{{tcping}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'{{id}}\', this, \'tcping\')"><%:Test%></a></span>');
|
||||
} else {
|
||||
innerHTML = innerHTML.split("{{tcping}}").join('<span class="tcping_value" cbiid="{{id}}">---</span>');
|
||||
innerHTML = innerHTML.split("{{tcping}}").join('<span class="tcping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
|
||||
}
|
||||
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)"><%:Test%></a></span>');
|
||||
innerHTML = innerHTML.split("{{id}}").join(o[".name"]);
|
||||
|
||||
@ -567,6 +567,9 @@ msgstr "نوع احراز هویت"
|
||||
msgid "Auth Password"
|
||||
msgstr "رمز عبور احراز هویت"
|
||||
|
||||
msgid "Client BBR Flow Control"
|
||||
msgstr "کنترل BBR مشتری"
|
||||
|
||||
msgid "Commands the client to use the BBR flow control algorithm"
|
||||
msgstr "به کلاینت دستور میدهد تا از الگوریتم کنترل جریان BBR استفاده کند"
|
||||
|
||||
@ -591,6 +594,9 @@ msgstr "پنجره دریافت اتصال QUIC"
|
||||
msgid "QUIC concurrent bidirectional streams"
|
||||
msgstr "جریانهای دوطرفه همزمان QUIC"
|
||||
|
||||
msgid "QUIC KeepAlive interval"
|
||||
msgstr "فاصله QUIC KeepAlive"
|
||||
|
||||
msgid "Disable MTU detection"
|
||||
msgstr "غیرفعال کردن تشخیص MTU"
|
||||
|
||||
@ -1335,6 +1341,9 @@ msgstr "اجازه ناامن (allowInsecure)"
|
||||
msgid "Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."
|
||||
msgstr "آیا اتصالات ناامن مجاز هستند. در صورت تیک خوردن، اعتبارسنجی گواهی نادیده گرفته میشود."
|
||||
|
||||
msgid "Used when the node link does not include this parameter."
|
||||
msgstr "زمانی استفاده میشود که لینک گره شامل این پارامتر نباشد."
|
||||
|
||||
msgid "%s Node Use Type"
|
||||
msgstr "نوع استفاده گره %s"
|
||||
|
||||
@ -1353,6 +1362,9 @@ msgstr "رمز عبور TUIC برای Socks محلی"
|
||||
msgid "UDP relay mode"
|
||||
msgstr "حالت بازپخش UDP"
|
||||
|
||||
msgid "Concurrent Tunnels"
|
||||
msgstr "تونلهای همزمان"
|
||||
|
||||
msgid "Congestion control algorithm"
|
||||
msgstr "الگوریتم کنترل ازدحام"
|
||||
|
||||
@ -1674,12 +1686,21 @@ msgstr "سیاست پرسوجوی ECH"
|
||||
msgid "Controls the policy used when performing DNS queries for ECH configuration."
|
||||
msgstr "سیاستی که هنگام انجام پرسوجوهای DNS برای پیکربندی ECH استفاده میشود را کنترل میکند."
|
||||
|
||||
msgid "ECH Query Domain"
|
||||
msgstr "دامنه پرس و جو ECH"
|
||||
|
||||
msgid "Overrides the domain name used for ECH HTTPS record queries."
|
||||
msgstr "نام دامنه مورد استفاده برای پرسوجوهای رکورد ECH HTTPS را لغو میکند."
|
||||
|
||||
msgid "Enable Multipath TCP, need to be enabled in both server and client configuration."
|
||||
msgstr "فعالسازی Multipath TCP، باید در تنظیمات سرور و کلاینت فعال باشد."
|
||||
|
||||
msgid "An FinalMaskObject in JSON format, used for sharing."
|
||||
msgstr "یک شیء FinalMaskObject با فرمت JSON که برای اشتراکگذاری استفاده میشود."
|
||||
|
||||
msgid "Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related settings."
|
||||
msgstr "ماسک نهایی سفارشی، تنظیمات mkcp، hysteria2، fragment، noise و تنظیمات مرتبط را نادیده میگیرد."
|
||||
|
||||
msgid "Fragment"
|
||||
msgstr "قطعهبندی (Fragment)"
|
||||
|
||||
@ -1698,8 +1719,8 @@ msgstr "طول قطعه"
|
||||
msgid "Fragmented packet length (byte)"
|
||||
msgstr "طول بسته قطعهبندی شده (بایت)"
|
||||
|
||||
msgid "Fragment Interval"
|
||||
msgstr "بازه قطعهبندی"
|
||||
msgid "Fragment Delay"
|
||||
msgstr "تأخیر قطعه"
|
||||
|
||||
msgid "Fragmentation interval (ms)"
|
||||
msgstr "بازه قطعهبندی (میلیثانیه)"
|
||||
@ -1708,7 +1729,7 @@ msgid "Max Split"
|
||||
msgstr "حداکثر تقسیم"
|
||||
|
||||
msgid "Limit the maximum number of splits."
|
||||
msgstr "محدود کردن حداکثر تعداد تقسیمها."
|
||||
msgstr "حداکثر تعداد تقسیمبندیها را محدود کنید."
|
||||
|
||||
msgid "Split handshake data into multiple TLS records for better censorship evasion. Low overhead. Recommended to enable first."
|
||||
msgstr "تقسیم دادههای دست تکان دادن به چندین رکورد TLS برای فرار بهتر از سانسور. سربار کم. توصیه میشود ابتدا فعال شود."
|
||||
@ -1728,15 +1749,12 @@ msgstr "برای ارسال بستههای نویز، \"Noise\" را در ت
|
||||
msgid "Xray Noise Packets"
|
||||
msgstr "بستههای نویز Xray"
|
||||
|
||||
msgid "Packet"
|
||||
msgstr "بسته"
|
||||
msgid "Packet | Rand Length"
|
||||
msgstr "طول بسته | رند"
|
||||
|
||||
msgid "Delay (ms)"
|
||||
msgstr "تاخیر (میلیثانیه)"
|
||||
|
||||
msgid "IP Type"
|
||||
msgstr "نوع IP"
|
||||
|
||||
msgid "If is domain name, The requested domain name will be resolved to IP before connect."
|
||||
msgstr "اگر نام دامنه است، نام دامنه درخواست شده قبل از اتصال به IP حل میشود."
|
||||
|
||||
@ -2275,6 +2293,9 @@ msgstr "گزینههای افزونه ناقص است."
|
||||
msgid "shadowsocks-libev unsupport 2022 encryption."
|
||||
msgstr "shadowsocks-libev از رمزنگاری 2022 پشتیبانی نمیکند."
|
||||
|
||||
msgid "Please replace %s to support %s transmission method."
|
||||
msgstr "لطفا برای پشتیبانی از روش انتقال %s، %s را جایگزین کنید."
|
||||
|
||||
msgid "Please replace Xray or Sing-Box to support more transmission methods in Shadowsocks."
|
||||
msgstr "لطفاً برای پشتیبانی از روشهای انتقال بیشتر در Shadowsocks، از Xray یا Sing-Box استفاده کنید."
|
||||
|
||||
@ -2361,3 +2382,6 @@ msgstr "خطا، بازیابی سرویس."
|
||||
|
||||
msgid "Subscription complete..."
|
||||
msgstr "اشتراک کامل شد..."
|
||||
|
||||
msgid "Processing, please wait…"
|
||||
msgstr "در حال پردازش، لطفا صبر کنید…"
|
||||
|
||||
@ -568,6 +568,9 @@ msgstr "Тип аутентификации"
|
||||
msgid "Auth Password"
|
||||
msgstr "Пароль аутентификации"
|
||||
|
||||
msgid "Client BBR Flow Control"
|
||||
msgstr "Управление клиентом BBR"
|
||||
|
||||
msgid "Commands the client to use the BBR flow control algorithm"
|
||||
msgstr "Включает использование алгоритма управления потоком BBR на клиенте"
|
||||
|
||||
@ -592,6 +595,9 @@ msgstr "Размер окна приёма соединения QUIC"
|
||||
msgid "QUIC concurrent bidirectional streams"
|
||||
msgstr "Макс. количество одновременных двунаправленных потоков QUIC"
|
||||
|
||||
msgid "QUIC KeepAlive interval"
|
||||
msgstr "Интервал QUIC KeepAlive"
|
||||
|
||||
msgid "Disable MTU detection"
|
||||
msgstr "Отключить определение MTU"
|
||||
|
||||
@ -1336,6 +1342,9 @@ msgstr "Пропускать проверку сертификата"
|
||||
msgid "Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."
|
||||
msgstr "Разрешить соединения без проверки сертификата. При включении валидация будет пропущена."
|
||||
|
||||
msgid "Used when the node link does not include this parameter."
|
||||
msgstr "Используется, если в ссылке на узел этот параметр отсутствует."
|
||||
|
||||
msgid "%s Node Use Type"
|
||||
msgstr "Тип использования сервера %s"
|
||||
|
||||
@ -1354,6 +1363,9 @@ msgstr "Пароль для локального SOCKS TUIC"
|
||||
msgid "UDP relay mode"
|
||||
msgstr "Режим ретрансляции UDP"
|
||||
|
||||
msgid "Concurrent Tunnels"
|
||||
msgstr "Одновременные туннели"
|
||||
|
||||
msgid "Congestion control algorithm"
|
||||
msgstr "Алгоритм контроля перегрузок"
|
||||
|
||||
@ -1675,12 +1687,21 @@ msgstr "Политика запросов ECH"
|
||||
msgid "Controls the policy used when performing DNS queries for ECH configuration."
|
||||
msgstr "Управляет политикой DNS-запросов для получения конфигурации ECH."
|
||||
|
||||
msgid "ECH Query Domain"
|
||||
msgstr "Домен запроса ECH"
|
||||
|
||||
msgid "Overrides the domain name used for ECH HTTPS record queries."
|
||||
msgstr "Переопределяет доменное имя, используемое для запросов записей ECH HTTPS."
|
||||
|
||||
msgid "Enable Multipath TCP, need to be enabled in both server and client configuration."
|
||||
msgstr "Включить Multipath TCP. Должно быть активировано и на сервере, и на клиенте."
|
||||
|
||||
msgid "An FinalMaskObject in JSON format, used for sharing."
|
||||
msgstr "Объект FinalMaskObject в формате JSON, используемый для обмена данными."
|
||||
|
||||
msgid "Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related settings."
|
||||
msgstr "Пользовательская настройка finalmask переопределяет параметры mkcp, hysteria2, fragment, noise и связанные с ними настройки."
|
||||
|
||||
msgid "Fragment"
|
||||
msgstr "Фрагментация"
|
||||
|
||||
@ -1699,17 +1720,17 @@ msgstr "Длина фрагмента"
|
||||
msgid "Fragmented packet length (byte)"
|
||||
msgstr "Длина фрагментированного пакета (байт)"
|
||||
|
||||
msgid "Fragment Interval"
|
||||
msgstr "Интервал фрагментации"
|
||||
msgid "Fragment Delay"
|
||||
msgstr "Задержка фрагмента"
|
||||
|
||||
msgid "Fragmentation interval (ms)"
|
||||
msgstr "Интервал между фрагментами (мс)"
|
||||
|
||||
msgid "Max Split"
|
||||
msgstr "Макс. число фрагментов"
|
||||
msgstr "Максимальное разделение"
|
||||
|
||||
msgid "Limit the maximum number of splits."
|
||||
msgstr "Ограничить максимальное количество фрагментов."
|
||||
msgstr "Ограничьте максимальное количество разделений."
|
||||
|
||||
msgid "Split handshake data into multiple TLS records for better censorship evasion. Low overhead. Recommended to enable first."
|
||||
msgstr "Разбивать данные рукопожатия на несколько TLS-записей для лучшего обхода цензуры. Малая нагрузка. Рекомендуется включить в первую очередь."
|
||||
@ -1729,15 +1750,12 @@ msgstr "Чтобы отправлять шумовые пакеты, включ
|
||||
msgid "Xray Noise Packets"
|
||||
msgstr "Пакеты шума Xray"
|
||||
|
||||
msgid "Packet"
|
||||
msgstr "Пакет"
|
||||
msgid "Packet | Rand Length"
|
||||
msgstr "Пакет | Длина ранда"
|
||||
|
||||
msgid "Delay (ms)"
|
||||
msgstr "Задержка (мс)"
|
||||
|
||||
msgid "IP Type"
|
||||
msgstr "Тип IP"
|
||||
|
||||
msgid "If is domain name, The requested domain name will be resolved to IP before connect."
|
||||
msgstr "Если указано доменное имя, оно будет разрешено в IP-адрес перед подключением."
|
||||
|
||||
@ -2273,6 +2291,9 @@ msgstr "Опции плагина указаны не полностью."
|
||||
msgid "shadowsocks-libev unsupport 2022 encryption."
|
||||
msgstr "shadowsocks-libev не поддерживает шифрование 2022."
|
||||
|
||||
msgid "Please replace %s to support %s transmission method."
|
||||
msgstr "Пожалуйста, замените %s, чтобы поддержать метод передачи %s."
|
||||
|
||||
msgid "Please replace Xray or Sing-Box to support more transmission methods in Shadowsocks."
|
||||
msgstr "Пожалуйста, используйте Xray или Sing-Box для поддержки дополнительных методов передачи в Shadowsocks."
|
||||
|
||||
@ -2359,3 +2380,6 @@ msgstr "Ошибка, выполняется восстановление слу
|
||||
|
||||
msgid "Subscription complete..."
|
||||
msgstr "Подписка завершена..."
|
||||
|
||||
msgid "Processing, please wait…"
|
||||
msgstr "Обработка, пожалуйста, подождите…"
|
||||
@ -559,6 +559,9 @@ msgstr "认证类型"
|
||||
msgid "Auth Password"
|
||||
msgstr "认证密码"
|
||||
|
||||
msgid "Client BBR Flow Control"
|
||||
msgstr "客户端 BBR 流控"
|
||||
|
||||
msgid "Commands the client to use the BBR flow control algorithm"
|
||||
msgstr "命令客户端使用 BBR 流量控制算法"
|
||||
|
||||
@ -583,6 +586,9 @@ msgstr "QUIC 连接接收窗口"
|
||||
msgid "QUIC concurrent bidirectional streams"
|
||||
msgstr "QUIC 并发双向流的最大数量"
|
||||
|
||||
msgid "QUIC KeepAlive interval"
|
||||
msgstr "QUIC KeepAlive 间隔"
|
||||
|
||||
msgid "Disable MTU detection"
|
||||
msgstr "禁用 MTU 检测"
|
||||
|
||||
@ -1327,6 +1333,9 @@ msgstr "允许不安全连接"
|
||||
msgid "Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."
|
||||
msgstr "是否允许不安全连接。当勾选时,将跳过证书验证。"
|
||||
|
||||
msgid "Used when the node link does not include this parameter."
|
||||
msgstr "当节点链接未包含该参数时,将使用此设置。"
|
||||
|
||||
msgid "%s Node Use Type"
|
||||
msgstr "%s 节点使用类型"
|
||||
|
||||
@ -1345,6 +1354,9 @@ msgstr "用于本地Socks服务器连接的密码"
|
||||
msgid "UDP relay mode"
|
||||
msgstr "UDP中继模式"
|
||||
|
||||
msgid "Concurrent Tunnels"
|
||||
msgstr "并发隧道连接数"
|
||||
|
||||
msgid "Congestion control algorithm"
|
||||
msgstr "拥塞控制算法"
|
||||
|
||||
@ -1666,12 +1678,21 @@ msgstr "ECH 查询策略"
|
||||
msgid "Controls the policy used when performing DNS queries for ECH configuration."
|
||||
msgstr "控制使用 DNS 查询 ECH 配置时的策略。"
|
||||
|
||||
msgid "ECH Query Domain"
|
||||
msgstr "ECH 查询域名"
|
||||
|
||||
msgid "Overrides the domain name used for ECH HTTPS record queries."
|
||||
msgstr "覆盖用于 ECH HTTPS 记录查询的域名。"
|
||||
|
||||
msgid "Enable Multipath TCP, need to be enabled in both server and client configuration."
|
||||
msgstr "启用 Multipath TCP,需在服务端和客户端配置中同时启用。"
|
||||
|
||||
msgid "An FinalMaskObject in JSON format, used for sharing."
|
||||
msgstr "JSON 格式的 FinalMaskObject,用来实现分享。"
|
||||
|
||||
msgid "Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related settings."
|
||||
msgstr "自定义 finalmask 将覆盖 mkcp、hysteria2、fragment、noise 等相关配置。"
|
||||
|
||||
msgid "Fragment"
|
||||
msgstr "分片"
|
||||
|
||||
@ -1690,8 +1711,8 @@ msgstr "分片包长"
|
||||
msgid "Fragmented packet length (byte)"
|
||||
msgstr "分片包长 (byte)"
|
||||
|
||||
msgid "Fragment Interval"
|
||||
msgstr "分片间隔"
|
||||
msgid "Fragment Delay"
|
||||
msgstr "分片延迟"
|
||||
|
||||
msgid "Fragmentation interval (ms)"
|
||||
msgstr "分片间隔(ms)"
|
||||
@ -1720,15 +1741,12 @@ msgstr "在 Xray 设置中勾选 “噪声” 以发送噪声包。"
|
||||
msgid "Xray Noise Packets"
|
||||
msgstr "Xray 噪声数据包"
|
||||
|
||||
msgid "Packet"
|
||||
msgstr "数据包"
|
||||
msgid "Packet | Rand Length"
|
||||
msgstr "数据包 | Rand 长度"
|
||||
|
||||
msgid "Delay (ms)"
|
||||
msgstr "延迟(ms)"
|
||||
|
||||
msgid "IP Type"
|
||||
msgstr "IP 类型"
|
||||
|
||||
msgid "If is domain name, The requested domain name will be resolved to IP before connect."
|
||||
msgstr "如果是域名,域名将在请求发出之前解析为 IP。"
|
||||
|
||||
@ -2267,6 +2285,9 @@ msgstr "插件选项不完整。"
|
||||
msgid "shadowsocks-libev unsupport 2022 encryption."
|
||||
msgstr "shadowsocks-libev 不支持2022加密。"
|
||||
|
||||
msgid "Please replace %s to support %s transmission method."
|
||||
msgstr "请更换 %s 以支持 %s 传输方式。"
|
||||
|
||||
msgid "Please replace Xray or Sing-Box to support more transmission methods in Shadowsocks."
|
||||
msgstr "请更换 Xray 或 Sing-Box 来支持 Shadowsocks 更多的传输方式。"
|
||||
|
||||
@ -2353,3 +2374,6 @@ msgstr "发生错误, 正在恢复服务。"
|
||||
|
||||
msgid "Subscription complete..."
|
||||
msgstr "订阅完毕..."
|
||||
|
||||
msgid "Processing, please wait…"
|
||||
msgstr "正在处理,请稍候。"
|
||||
|
||||
@ -559,6 +559,9 @@ msgstr "認證類型"
|
||||
msgid "Auth Password"
|
||||
msgstr "認證密碼"
|
||||
|
||||
msgid "Client BBR Flow Control"
|
||||
msgstr "客戶端 BBR 流控"
|
||||
|
||||
msgid "Commands the client to use the BBR flow control algorithm"
|
||||
msgstr "命令客戶端使用 BBR 流量控制算法"
|
||||
|
||||
@ -583,6 +586,9 @@ msgstr "QUIC 連接接收窗口"
|
||||
msgid "QUIC concurrent bidirectional streams"
|
||||
msgstr "QUIC 並發双向流的最大數量"
|
||||
|
||||
msgid "QUIC KeepAlive interval"
|
||||
msgstr "QUIC KeepAlive 間隔"
|
||||
|
||||
msgid "Disable MTU detection"
|
||||
msgstr "禁用 MTU 檢測"
|
||||
|
||||
@ -1327,6 +1333,9 @@ msgstr "允許不安全連接"
|
||||
msgid "Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."
|
||||
msgstr "是否允許不安全連接。當勾選時,將跳過證書驗證。"
|
||||
|
||||
msgid "Used when the node link does not include this parameter."
|
||||
msgstr "當節點連結未包含該參數時,將使用此設定。"
|
||||
|
||||
msgid "%s Node Use Type"
|
||||
msgstr "%s 節點使用類型"
|
||||
|
||||
@ -1345,6 +1354,9 @@ msgstr "用於本地Socks服務器連接的密碼"
|
||||
msgid "UDP relay mode"
|
||||
msgstr "UDP中继模式"
|
||||
|
||||
msgid "Concurrent Tunnels"
|
||||
msgstr "並發隧道連接數"
|
||||
|
||||
msgid "Congestion control algorithm"
|
||||
msgstr "拥塞控制算法"
|
||||
|
||||
@ -1666,12 +1678,21 @@ msgstr "ECH 查詢策略"
|
||||
msgid "Controls the policy used when performing DNS queries for ECH configuration."
|
||||
msgstr "控制使用 DNS 查詢 ECH 配置時的策略。"
|
||||
|
||||
msgid "ECH Query Domain"
|
||||
msgstr "ECH 查詢網域名"
|
||||
|
||||
msgid "Overrides the domain name used for ECH HTTPS record queries."
|
||||
msgstr "覆蓋用於 ECH HTTPS 記錄查詢的網域名。"
|
||||
|
||||
msgid "Enable Multipath TCP, need to be enabled in both server and client configuration."
|
||||
msgstr "啟用 Multipath TCP,需在服務端和客戶端配置中同時啟用。"
|
||||
|
||||
msgid "An FinalMaskObject in JSON format, used for sharing."
|
||||
msgstr "JSON 格式的 FinalMaskObject,用來實現分享。"
|
||||
|
||||
msgid "Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related settings."
|
||||
msgstr "自定義 finalmask 將涵蓋 mkcp、hysteria2、fragment、noise 等相關配置。"
|
||||
|
||||
msgid "Fragment"
|
||||
msgstr "分片"
|
||||
|
||||
@ -1690,8 +1711,8 @@ msgstr "分片包长"
|
||||
msgid "Fragmented packet length (byte)"
|
||||
msgstr "分片包长 (byte)"
|
||||
|
||||
msgid "Fragment Interval"
|
||||
msgstr "分片間隔"
|
||||
msgid "Fragment Delay"
|
||||
msgstr "分片延遲"
|
||||
|
||||
msgid "Fragmentation interval (ms)"
|
||||
msgstr "分片間隔(ms)"
|
||||
@ -1720,15 +1741,12 @@ msgstr "在 Xray 設置中勾選 “噪聲” 以發送噪聲包。"
|
||||
msgid "Xray Noise Packets"
|
||||
msgstr "Xray 噪聲數据包"
|
||||
|
||||
msgid "Packet"
|
||||
msgstr "數据包"
|
||||
msgid "Packet | Rand Length"
|
||||
msgstr "數據包 | Rand 長度"
|
||||
|
||||
msgid "Delay (ms)"
|
||||
msgstr "延迟(ms)"
|
||||
|
||||
msgid "IP Type"
|
||||
msgstr "IP 類型"
|
||||
|
||||
msgid "If is domain name, The requested domain name will be resolved to IP before connect."
|
||||
msgstr "如果是域名,域名將在請求發出之前解析為 IP。"
|
||||
|
||||
@ -2267,8 +2285,11 @@ msgstr "插件選項不完整。"
|
||||
msgid "shadowsocks-libev unsupport 2022 encryption."
|
||||
msgstr "shadowsocks-libev 不支持2022加密。"
|
||||
|
||||
msgid "Please replace %s to support %s transmission method."
|
||||
msgstr "請更換 %s 以支援 %s 傳輸方式。"
|
||||
|
||||
msgid "Please replace Xray or Sing-Box to support more transmission methods in Shadowsocks."
|
||||
msgstr "請更換 Xray 或 Sing-Box 來支持 Shadowsocks 更多的傳輸方式。"
|
||||
msgstr "請更換 Xray 或 Sing-Box 來支援 Shadowsocks 更多的傳輸方式。"
|
||||
|
||||
msgid "unsupport %s plugin."
|
||||
msgstr "不支持 %s 插件。"
|
||||
@ -2353,3 +2374,6 @@ msgstr "發生錯誤, 正在恢復服務。"
|
||||
|
||||
msgid "Subscription complete..."
|
||||
msgstr "訂閱完毕..."
|
||||
|
||||
msgid "Processing, please wait…"
|
||||
msgstr "正在處理,請稍候。"
|
||||
|
||||
@ -13,6 +13,8 @@ IPSET_WAN6="passwall2_wan6"
|
||||
IPSET_LAN6="passwall2_lan6"
|
||||
IPSET_VPS6="passwall2_vps6"
|
||||
|
||||
FWMARK="0x50535732"
|
||||
|
||||
ipt=$(command -v iptables-legacy || command -v iptables)
|
||||
ip6t=$(command -v ip6tables-legacy || command -v ip6tables)
|
||||
|
||||
@ -150,10 +152,9 @@ REDIRECT() {
|
||||
local s="-j REDIRECT"
|
||||
[ -n "$1" ] && {
|
||||
local s="$s --to-ports $1"
|
||||
[ "$2" == "MARK" ] && s="-j MARK --set-mark $1"
|
||||
[ "$2" == "TPROXY" ] && {
|
||||
local mark="-m mark --mark 1"
|
||||
s="${mark} -j TPROXY --tproxy-mark 0x1/0x1 --on-port $1"
|
||||
local mark="-m mark --mark ${FWMARK}"
|
||||
s="${mark} -j TPROXY --on-port $1"
|
||||
}
|
||||
}
|
||||
echo $s
|
||||
@ -688,7 +689,7 @@ add_firewall_rule() {
|
||||
$ipt_n -N PSW2_OUTPUT
|
||||
$ipt_n -A PSW2_OUTPUT $(dst $IPSET_LAN) -j RETURN
|
||||
$ipt_n -A PSW2_OUTPUT $(dst $IPSET_VPS) -j RETURN
|
||||
$ipt_n -A PSW2_OUTPUT -m mark --mark 0xff -j RETURN
|
||||
$ipt_n -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||
|
||||
$ipt_n -N PSW2_DNS
|
||||
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
|
||||
@ -697,12 +698,16 @@ add_firewall_rule() {
|
||||
else
|
||||
$ipt_n -I PREROUTING -j PSW2_DNS
|
||||
fi
|
||||
|
||||
|
||||
$ipt_m -N PSW2_DIVERT
|
||||
$ipt_m -A PSW2_DIVERT -j MARK --set-mark ${FWMARK}
|
||||
$ipt_m -A PSW2_DIVERT -j ACCEPT
|
||||
|
||||
$ipt_m -N PSW2_RULE
|
||||
$ipt_m -A PSW2_RULE -j CONNMARK --restore-mark
|
||||
$ipt_m -A PSW2_RULE -m mark --mark 0x1 -j RETURN
|
||||
$ipt_m -A PSW2_RULE -p tcp -m tcp --syn -j MARK --set-xmark 1
|
||||
$ipt_m -A PSW2_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark 1
|
||||
$ipt_m -A PSW2_RULE -m mark --mark ${FWMARK} -j RETURN
|
||||
$ipt_m -A PSW2_RULE -p tcp -m tcp --syn -j MARK --set-xmark ${FWMARK}
|
||||
$ipt_m -A PSW2_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark ${FWMARK}
|
||||
$ipt_m -A PSW2_RULE -j CONNMARK --save-mark
|
||||
|
||||
$ipt_m -N PSW2
|
||||
@ -722,6 +727,8 @@ add_firewall_rule() {
|
||||
unset WAN_IP wan_ip
|
||||
|
||||
insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW2"
|
||||
insert_rule_before "$ipt_m" "PREROUTING" "PSW2" "-p tcp -m socket -j PSW2_DIVERT"
|
||||
insert_rule_before "$ipt_m" "PREROUTING" "PSW2" "-p udp -m socket -j PSW2_DIVERT"
|
||||
|
||||
$ipt_m -N PSW2_OUTPUT
|
||||
$ipt_m -A PSW2_OUTPUT $(dst $IPSET_LAN) -j RETURN
|
||||
@ -735,10 +742,10 @@ add_firewall_rule() {
|
||||
log_i18n 1 "$(i18n "Add direct DNS to %s: %s" "iptables" "${dns_address}:${dns_port:-53}")"
|
||||
done
|
||||
}
|
||||
$ipt_m -A PSW2_OUTPUT -m mark --mark 0xff -j RETURN
|
||||
$ipt_m -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||
|
||||
ip rule add fwmark 1 lookup 100
|
||||
ip route add local 0.0.0.0/0 dev lo table 100
|
||||
ip rule add fwmark ${FWMARK} lookup 999 priority 999
|
||||
ip route add local 0.0.0.0/0 dev lo table 999
|
||||
|
||||
[ "$accept_icmpv6" = "1" ] && {
|
||||
$ip6t_n -N PSW2
|
||||
@ -749,7 +756,7 @@ add_firewall_rule() {
|
||||
$ip6t_n -N PSW2_OUTPUT
|
||||
$ip6t_n -A PSW2_OUTPUT $(dst $IPSET_LAN6) -j RETURN
|
||||
$ip6t_n -A PSW2_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
||||
$ip6t_n -A PSW2_OUTPUT -m mark --mark 0xff -j RETURN
|
||||
$ip6t_n -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||
}
|
||||
|
||||
$ip6t_n -N PSW2_DNS
|
||||
@ -759,12 +766,16 @@ add_firewall_rule() {
|
||||
else
|
||||
$ip6t_n -I PREROUTING -j PSW2_DNS
|
||||
fi
|
||||
|
||||
$ip6t_m -N PSW2_DIVERT
|
||||
$ip6t_m -A PSW2_DIVERT -j MARK --set-mark ${FWMARK}
|
||||
$ip6t_m -A PSW2_DIVERT -j ACCEPT
|
||||
|
||||
$ip6t_m -N PSW2_RULE
|
||||
$ip6t_m -A PSW2_RULE -j CONNMARK --restore-mark
|
||||
$ip6t_m -A PSW2_RULE -m mark --mark 0x1 -j RETURN
|
||||
$ip6t_m -A PSW2_RULE -p tcp -m tcp --syn -j MARK --set-xmark 1
|
||||
$ip6t_m -A PSW2_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark 1
|
||||
$ip6t_m -A PSW2_RULE -m mark --mark ${FWMARK} -j RETURN
|
||||
$ip6t_m -A PSW2_RULE -p tcp -m tcp --syn -j MARK --set-xmark ${FWMARK}
|
||||
$ip6t_m -A PSW2_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark ${FWMARK}
|
||||
$ip6t_m -A PSW2_RULE -j CONNMARK --save-mark
|
||||
|
||||
$ip6t_m -N PSW2
|
||||
@ -783,15 +794,17 @@ add_firewall_rule() {
|
||||
unset WAN6_IP wan6_ip
|
||||
|
||||
insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "-j PSW2"
|
||||
insert_rule_before "$ip6t_m" "PREROUTING" "PSW2" "-p tcp -m socket -j PSW2_DIVERT"
|
||||
insert_rule_before "$ip6t_m" "PREROUTING" "PSW2" "-p udp -m socket -j PSW2_DIVERT"
|
||||
|
||||
$ip6t_m -N PSW2_OUTPUT
|
||||
$ip6t_m -A PSW2_OUTPUT -m mark --mark 0xff -j RETURN
|
||||
$ip6t_m -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||
$ip6t_m -A PSW2_OUTPUT $(dst $IPSET_LAN6) -j RETURN
|
||||
$ip6t_m -A PSW2_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
||||
$ip6t_m -A PSW2_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
||||
|
||||
ip -6 rule add fwmark 1 table 100
|
||||
ip -6 route add local ::/0 dev lo table 100
|
||||
ip -6 rule add fwmark ${FWMARK} table 999 priority 999
|
||||
ip -6 route add local ::/0 dev lo table 999
|
||||
|
||||
[ "$ENABLED_DEFAULT_ACL" == 1 ] && {
|
||||
local ipt_tmp=$ipt_n
|
||||
@ -910,10 +923,10 @@ add_firewall_rule() {
|
||||
fi
|
||||
|
||||
$ipt_m -I OUTPUT $(comment "mangle-OUTPUT-PSW2") -o lo -j RETURN
|
||||
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark 1 -j RETURN"
|
||||
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark ${FWMARK} -j RETURN"
|
||||
|
||||
$ip6t_m -I OUTPUT $(comment "mangle-OUTPUT-PSW2") -o lo -j RETURN
|
||||
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark 1 -j RETURN"
|
||||
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark ${FWMARK} -j RETURN"
|
||||
|
||||
$ipt_m -A PSW2 -p udp --dport 53 -j RETURN
|
||||
$ip6t_m -A PSW2 -p udp --dport 53 -j RETURN
|
||||
@ -934,17 +947,17 @@ del_firewall_rule() {
|
||||
$ipt -D $chain $index 2>/dev/null
|
||||
done
|
||||
done
|
||||
for chain in "PSW2" "PSW2_OUTPUT" "PSW2_DNS" "PSW2_RULE"; do
|
||||
for chain in "PSW2" "PSW2_OUTPUT" "PSW2_DIVERT" "PSW2_DNS" "PSW2_RULE"; do
|
||||
$ipt -F $chain 2>/dev/null
|
||||
$ipt -X $chain 2>/dev/null
|
||||
done
|
||||
done
|
||||
|
||||
ip rule del fwmark 1 lookup 100 2>/dev/null
|
||||
ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
|
||||
ip rule del fwmark ${FWMARK} lookup 999 priority 999 2>/dev/null
|
||||
ip route del local 0.0.0.0/0 dev lo table 999 2>/dev/null
|
||||
|
||||
ip -6 rule del fwmark 1 table 100 2>/dev/null
|
||||
ip -6 route del local ::/0 dev lo table 100 2>/dev/null
|
||||
ip -6 rule del fwmark ${FWMARK} table 999 priority 999 2>/dev/null
|
||||
ip -6 route del local ::/0 dev lo table 999 2>/dev/null
|
||||
|
||||
log_i18n 0 "Delete %s rules is complete." "iptables"
|
||||
}
|
||||
@ -968,7 +981,7 @@ gen_include() {
|
||||
[ -z "${_ipt}" ] && return
|
||||
|
||||
echo "*$2"
|
||||
${_ipt}-save -t $2 | grep "PSW2" | grep -v "\-j PSW2$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
||||
${_ipt}-save -t $2 | grep "PSW2" | grep -v "\-j PSW2$" | grep -v "socket \-j PSW2_DIVERT$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
||||
echo 'COMMIT'
|
||||
}
|
||||
local __ipt=""
|
||||
@ -985,6 +998,8 @@ gen_include() {
|
||||
[ -z "${is_tproxy}" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p tcp -j PSW2")
|
||||
|
||||
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW2")
|
||||
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "PSW2" "-p tcp -m socket -j PSW2_DIVERT")
|
||||
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "PSW2" "-p udp -m socket -j PSW2_DIVERT")
|
||||
|
||||
WAN_IP=\$(get_wan_ips ip4)
|
||||
[ ! -z "\${WAN_IP}" ] && {
|
||||
@ -1009,6 +1024,8 @@ gen_include() {
|
||||
[ "$accept_icmpv6" = "1" ] && $ip6t_n -A PREROUTING -p ipv6-icmp -j PSW2
|
||||
|
||||
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "-j PSW2")
|
||||
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "PSW2" "-p tcp -m socket -j PSW2_DIVERT")
|
||||
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "PSW2" "-p udp -m socket -j PSW2_DIVERT")
|
||||
|
||||
WAN6_IP=\$(get_wan_ips ip6)
|
||||
[ ! -z "\${WAN6_IP}" ] && {
|
||||
|
||||
@ -14,6 +14,8 @@ NFTSET_WAN6="passwall2_wan6"
|
||||
NFTSET_LAN6="passwall2_lan6"
|
||||
NFTSET_VPS6="passwall2_vps6"
|
||||
|
||||
FWMARK="0x50535732"
|
||||
|
||||
FWI=$(uci -q get firewall.passwall2.path 2>/dev/null)
|
||||
FAKE_IP="198.18.0.0/16"
|
||||
FAKE_IP_6="fc00::/18"
|
||||
@ -103,15 +105,14 @@ REDIRECT() {
|
||||
local s="counter redirect"
|
||||
[ -n "$1" ] && {
|
||||
local s="$s to :$1"
|
||||
[ "$2" == "MARK" ] && s="counter meta mark set $1"
|
||||
[ "$2" == "TPROXY" ] && {
|
||||
s="counter meta mark 1 tproxy to :$1"
|
||||
s="counter meta mark ${FWMARK} tproxy to :$1"
|
||||
}
|
||||
[ "$2" == "TPROXY4" ] && {
|
||||
s="counter meta mark 1 tproxy ip to :$1"
|
||||
s="counter meta mark ${FWMARK} tproxy ip to :$1"
|
||||
}
|
||||
[ "$2" == "TPROXY6" ] && {
|
||||
s="counter meta mark 1 tproxy ip6 to :$1"
|
||||
s="counter meta mark ${FWMARK} tproxy ip6 to :$1"
|
||||
}
|
||||
|
||||
}
|
||||
@ -500,7 +501,7 @@ load_acl() {
|
||||
|
||||
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && {
|
||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp $(factor $UDP_NO_REDIR_PORTS "udp dport") counter return comment \"${comment}\""
|
||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 counter meta l4proto udp $(factor $UDP_NO_REDIR_PORTS "udp dport") counter return comment \"${comment}\""
|
||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp $(factor $UDP_NO_REDIR_PORTS "udp dport") counter return comment \"${comment}\""
|
||||
if ! has_1_65535 "$UDP_NO_REDIR_PORTS"; then
|
||||
log 2 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${UDP_NO_REDIR_PORTS}")"
|
||||
else
|
||||
@ -712,6 +713,11 @@ add_firewall_rule() {
|
||||
nft_output_chain="PSW2_OUTPUT_MANGLE"
|
||||
fi
|
||||
|
||||
nft "add chain $NFTABLE_NAME PSW2_DIVERT"
|
||||
nft "flush chain $NFTABLE_NAME PSW2_DIVERT"
|
||||
nft "add rule $NFTABLE_NAME PSW2_DIVERT meta l4proto tcp socket transparent 1 mark set ${FWMARK} counter accept"
|
||||
nft "add rule $NFTABLE_NAME PSW2_DIVERT meta l4proto udp socket transparent 1 mark set ${FWMARK} counter accept"
|
||||
|
||||
nft "add chain $NFTABLE_NAME PSW2_DNS"
|
||||
nft "flush chain $NFTABLE_NAME PSW2_DNS"
|
||||
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
|
||||
@ -725,11 +731,11 @@ add_firewall_rule() {
|
||||
# for ipv4 ipv6 tproxy mark
|
||||
nft "add chain $NFTABLE_NAME PSW2_RULE"
|
||||
nft "flush chain $NFTABLE_NAME PSW2_RULE"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE meta mark set ct mark counter"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE meta mark 1 counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE tcp flags syn meta mark set mark and 0x0 xor 0x1 counter"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE meta l4proto udp ct state new,related meta mark set mark and 0x0 xor 0x1 counter"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE ct mark set mark counter"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE counter meta mark set ct mark"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE meta mark ${FWMARK} counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE tcp flags & (fin|syn|rst|ack) == syn counter meta mark set ${FWMARK}"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE meta l4proto udp ct state new,related counter meta mark set ${FWMARK}"
|
||||
nft "add rule $NFTABLE_NAME PSW2_RULE counter ct mark set mark"
|
||||
|
||||
#ipv4 tproxy mode and udp
|
||||
nft "add chain $NFTABLE_NAME PSW2_MANGLE"
|
||||
@ -751,9 +757,10 @@ add_firewall_rule() {
|
||||
log_i18n 1 "$(i18n "Add direct DNS to %s: %s" "nftables" "${dns_address}:${dns_port:-53}")"
|
||||
done
|
||||
}
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE meta mark 0xff counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE meta mark 255 counter return"
|
||||
|
||||
# jump chains
|
||||
nft "add rule $NFTABLE_NAME mangle_prerouting counter jump PSW2_DIVERT"
|
||||
nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol udp counter jump PSW2_MANGLE"
|
||||
[ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol tcp counter jump PSW2_MANGLE"
|
||||
|
||||
@ -769,7 +776,7 @@ add_firewall_rule() {
|
||||
nft "flush chain $NFTABLE_NAME PSW2_OUTPUT_NAT"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT ip daddr @$NFTSET_LAN counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT ip daddr @$NFTSET_VPS counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT meta mark 0xff counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT meta mark 255 counter return"
|
||||
}
|
||||
|
||||
#icmp ipv6-icmp redirect
|
||||
@ -797,8 +804,8 @@ add_firewall_rule() {
|
||||
}
|
||||
unset WAN_IP
|
||||
|
||||
ip rule add fwmark 1 lookup 100
|
||||
ip route add local 0.0.0.0/0 dev lo table 100
|
||||
ip rule add fwmark ${FWMARK} lookup 999 priority 999
|
||||
ip route add local 0.0.0.0/0 dev lo table 999
|
||||
|
||||
#ipv6 tproxy mode and udp
|
||||
nft "add chain $NFTABLE_NAME PSW2_MANGLE_V6"
|
||||
@ -812,7 +819,7 @@ add_firewall_rule() {
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_LAN6 counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ct direction reply counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta mark 0xff counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta mark 255 counter return"
|
||||
|
||||
# jump chains
|
||||
[ "$PROXY_IPV6" == "1" ] && {
|
||||
@ -827,8 +834,8 @@ add_firewall_rule() {
|
||||
}
|
||||
unset WAN6_IP
|
||||
|
||||
ip -6 rule add fwmark 1 table 100
|
||||
ip -6 route add local ::/0 dev lo table 100
|
||||
ip -6 rule add fwmark ${FWMARK} table 999 priority 999
|
||||
ip -6 route add local ::/0 dev lo table 999
|
||||
}
|
||||
|
||||
[ "$ENABLED_DEFAULT_ACL" == 1 ] && {
|
||||
@ -945,7 +952,7 @@ add_firewall_rule() {
|
||||
fi
|
||||
|
||||
nft "add rule $NFTABLE_NAME mangle_output oif lo counter return comment \"PSW2_OUTPUT_MANGLE\""
|
||||
nft "add rule $NFTABLE_NAME mangle_output meta mark 1 counter return comment \"PSW2_OUTPUT_MANGLE\""
|
||||
nft "add rule $NFTABLE_NAME mangle_output meta mark ${FWMARK} counter return comment \"PSW2_OUTPUT_MANGLE\""
|
||||
|
||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp udp dport 53 counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp udp dport 53 counter return"
|
||||
@ -973,11 +980,11 @@ del_firewall_rule() {
|
||||
# Need to be removed at the end, otherwise it will show "Resource busy"
|
||||
nft delete chain $NFTABLE_NAME handle $(nft -a list chains | grep -E "PSW2_RULE" | awk -F '# handle ' '{print$2}') 2>/dev/null
|
||||
|
||||
ip rule del fwmark 1 lookup 100 2>/dev/null
|
||||
ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
|
||||
ip rule del fwmark ${FWMARK} lookup 999 priority 999 2>/dev/null
|
||||
ip route del local 0.0.0.0/0 dev lo table 999 2>/dev/null
|
||||
|
||||
ip -6 rule del fwmark 1 table 100 2>/dev/null
|
||||
ip -6 route del local ::/0 dev lo table 100 2>/dev/null
|
||||
ip -6 rule del fwmark ${FWMARK} table 999 priority 999 2>/dev/null
|
||||
ip -6 route del local ::/0 dev lo table 999 2>/dev/null
|
||||
|
||||
destroy_nftset $NFTSET_LOCAL
|
||||
destroy_nftset $NFTSET_WAN
|
||||
|
||||
@ -453,7 +453,7 @@ local function processData(szType, content, add_mode, group)
|
||||
end
|
||||
result.type = "SSR"
|
||||
|
||||
local dat = split(content, "/%?")
|
||||
local dat = split(content:gsub("/%?", "?"), "%?")
|
||||
local hostInfo = split(dat[1], ':')
|
||||
if dat[1]:match('%[(.*)%]') then
|
||||
result.address = dat[1]:match('%[(.*)%]')
|
||||
@ -467,8 +467,10 @@ local function processData(szType, content, add_mode, group)
|
||||
result.password = base64Decode(hostInfo[#hostInfo])
|
||||
local params = {}
|
||||
for _, v in pairs(split(dat[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
params[t[1]] = t[2]
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1)] = v:sub(s + 1)
|
||||
end
|
||||
end
|
||||
result.obfs_param = base64Decode(params.obfsparam)
|
||||
result.protocol_param = base64Decode(params.protoparam)
|
||||
@ -587,14 +589,10 @@ local function processData(szType, content, add_mode, group)
|
||||
if info.tls == "tls" or info.tls == "1" then
|
||||
result.tls = "1"
|
||||
result.tls_serverName = (info.sni and info.sni ~= "") and info.sni or info.host
|
||||
info.allowinsecure = info.allowinsecure or info.insecure
|
||||
if info.allowinsecure and (info.allowinsecure == "1" or info.allowinsecure == "0") then
|
||||
result.tls_allowInsecure = info.allowinsecure
|
||||
else
|
||||
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
|
||||
end
|
||||
result.tls_CertSha = info.pcs
|
||||
result.tls_CertByName = info.vcn
|
||||
local insecure = info.allowinsecure or info.allowInsecure or info.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (allowInsecure_default and "1" or "0")
|
||||
else
|
||||
result.tls = "0"
|
||||
end
|
||||
@ -633,8 +631,10 @@ local function processData(szType, content, add_mode, group)
|
||||
local find_index = info:find("%?")
|
||||
local query = split(info, "%?")
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
if #t >= 2 then params[t[1]] = UrlDecode(t[2]) end
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1)] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
if params.plugin then
|
||||
local plugin_info = params.plugin
|
||||
@ -838,7 +838,7 @@ local function processData(szType, content, add_mode, group)
|
||||
end
|
||||
if params.type == 'xhttp' then
|
||||
if result.type ~= "Xray" then
|
||||
result.error_msg = "请更换 Xray 以支持 xhttp 传输方式."
|
||||
result.error_msg = i18n.translatef("Please replace %s to support %s transmission method.", "Xray", "xhttp")
|
||||
end
|
||||
result.xhttp_host = params.host
|
||||
result.xhttp_path = params.path
|
||||
@ -876,12 +876,8 @@ local function processData(szType, content, add_mode, group)
|
||||
result.reality_mldsa65Verify = params.pqv or nil
|
||||
end
|
||||
end
|
||||
params.allowinsecure = params.allowinsecure or params.insecure
|
||||
if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
|
||||
result.tls_allowInsecure = params.allowinsecure
|
||||
else
|
||||
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
|
||||
end
|
||||
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (allowInsecure_default and "1" or "0")
|
||||
result.uot = params.udp
|
||||
elseif (params.type ~= "tcp" and params.type ~= "raw") and (params.headerType and params.headerType ~= "none") then
|
||||
result.error_msg = i18n.translatef("Please replace Xray or Sing-Box to support more transmission methods in Shadowsocks.")
|
||||
@ -959,9 +955,9 @@ local function processData(szType, content, add_mode, group)
|
||||
local host_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
if #t > 1 then
|
||||
params[string.lower(t[1])] = UrlDecode(t[2])
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1)] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
-- [2001:4860:4860::8888]:443
|
||||
@ -978,32 +974,14 @@ local function processData(szType, content, add_mode, group)
|
||||
result.address = host_port
|
||||
end
|
||||
|
||||
local peer, sni = nil, ""
|
||||
if params.peer then peer = params.peer end
|
||||
sni = params.sni and params.sni or ""
|
||||
if params.ws and params.ws == "1" then
|
||||
result.trojan_transport = "ws"
|
||||
if params.wshost then result.ws_host = params.wshost end
|
||||
if params.wspath then result.ws_path = params.wspath end
|
||||
if sni == "" and params.wshost then sni = params.wshost end
|
||||
end
|
||||
result.port = port
|
||||
|
||||
result.tls = '1'
|
||||
result.tls_serverName = peer and peer or sni
|
||||
result.tls_serverName = params.peer or params.sni or ""
|
||||
result.tls_CertSha = params.pcs
|
||||
result.tls_CertByName = params.vcn
|
||||
|
||||
params.allowinsecure = params.allowinsecure or params.insecure
|
||||
if params.allowinsecure then
|
||||
if params.allowinsecure == "1" or params.allowinsecure == "0" then
|
||||
result.tls_allowInsecure = params.allowinsecure
|
||||
else
|
||||
result.tls_allowInsecure = string.lower(params.allowinsecure) == "true" and "1" or "0"
|
||||
end
|
||||
else
|
||||
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
|
||||
end
|
||||
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (allowInsecure_default and "1" or "0")
|
||||
|
||||
if not params.type then params.type = "tcp" end
|
||||
params.type = string.lower(params.type)
|
||||
@ -1071,8 +1049,7 @@ local function processData(szType, content, add_mode, group)
|
||||
result.quic_security = params.quicSecurity or "none"
|
||||
end
|
||||
if params.type == 'grpc' then
|
||||
if params.path then result.grpc_serviceName = params.path end
|
||||
if params.serviceName then result.grpc_serviceName = params.serviceName end
|
||||
result.grpc_serviceName = params.serviceName or params.path
|
||||
result.grpc_mode = params.mode or "gun"
|
||||
end
|
||||
if params.type == 'xhttp' then
|
||||
@ -1131,8 +1108,10 @@ local function processData(szType, content, add_mode, group)
|
||||
local host_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
params[t[1]] = UrlDecode(t[2])
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1)] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
-- [2001:4860:4860::8888]:443
|
||||
-- 8.8.8.8:443
|
||||
@ -1265,17 +1244,11 @@ local function processData(szType, content, add_mode, group)
|
||||
result.use_mldsa65Verify = (params.pqv and params.pqv ~= "") and "1" or nil
|
||||
result.reality_mldsa65Verify = params.pqv or nil
|
||||
end
|
||||
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (allowInsecure_default and "1" or "0")
|
||||
end
|
||||
|
||||
result.port = port
|
||||
|
||||
params.allowinsecure = params.allowinsecure or params.insecure
|
||||
if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
|
||||
result.tls_allowInsecure = params.allowinsecure
|
||||
else
|
||||
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
|
||||
end
|
||||
|
||||
result.tcp_fast_open = params.tfo
|
||||
result.use_finalmask = (params.fm and params.fm ~= "") and "1" or nil
|
||||
result.finalmask = (params.fm and params.fm ~= "") and api.base64Encode(params.fm) or nil
|
||||
@ -1302,13 +1275,13 @@ local function processData(szType, content, add_mode, group)
|
||||
end
|
||||
result.remarks = UrlDecode(alias)
|
||||
|
||||
local dat = split(content:gsub("/%?", "?"), '%?')
|
||||
local host_port = dat[1]
|
||||
local query = split(content:gsub("/%?", "?"), '%?')
|
||||
local host_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(dat[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
if #t > 0 then
|
||||
params[t[1]] = t[2]
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1)] = v:sub(s + 1)
|
||||
end
|
||||
end
|
||||
-- [2001:4860:4860::8888]:443
|
||||
@ -1327,14 +1300,10 @@ local function processData(szType, content, add_mode, group)
|
||||
result.hysteria_obfs = params.obfsParam
|
||||
result.hysteria_auth_type = "string"
|
||||
result.hysteria_auth_password = params.auth
|
||||
result.tls_serverName = params.peer
|
||||
params.allowinsecure = params.allowinsecure or params.insecure
|
||||
if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
|
||||
result.tls_allowInsecure = params.allowinsecure
|
||||
else
|
||||
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
|
||||
end
|
||||
result.hysteria_alpn = params.alpn
|
||||
result.tls_serverName = params.peer or params.sni or ""
|
||||
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (allowInsecure_default and "1" or "0")
|
||||
result.alpn = params.alpn
|
||||
result.hysteria_up_mbps = params.upmbps
|
||||
result.hysteria_down_mbps = params.downmbps
|
||||
result.hysteria_hop = params.mport
|
||||
@ -1357,9 +1326,9 @@ local function processData(szType, content, add_mode, group)
|
||||
local host_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
if #t > 1 then
|
||||
params[string.lower(t[1])] = UrlDecode(t[2])
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1):lower()] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
-- [2001:4860:4860::8888]:443
|
||||
@ -1378,12 +1347,8 @@ local function processData(szType, content, add_mode, group)
|
||||
result.tls_serverName = params.sni
|
||||
result.tls_CertSha = params.pcs
|
||||
result.tls_CertByName = params.vcn
|
||||
params.allowinsecure = params.allowinsecure or params.insecure
|
||||
if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
|
||||
result.tls_allowInsecure = params.allowinsecure
|
||||
else
|
||||
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
|
||||
end
|
||||
local insecure = params.allowinsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (allowInsecure_default and "1" or "0")
|
||||
result.hysteria2_tls_pinSHA256 = params.pinSHA256
|
||||
result.hysteria2_hop = params.mport
|
||||
|
||||
@ -1441,9 +1406,9 @@ local function processData(szType, content, add_mode, group)
|
||||
local host_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
if #t > 1 then
|
||||
params[string.lower(t[1])] = UrlDecode(t[2])
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1):lower()] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
if host_port:find(":") then
|
||||
@ -1462,16 +1427,8 @@ local function processData(szType, content, add_mode, group)
|
||||
result.tuic_alpn = params.alpn or "default"
|
||||
result.tuic_congestion_control = params.congestion_control or "cubic"
|
||||
result.tuic_udp_relay_mode = params.udp_relay_mode or "native"
|
||||
params.allowinsecure = params.allowinsecure or params.insecure
|
||||
if params.allowinsecure then
|
||||
if params.allowinsecure == "1" or params.allowinsecure == "0" then
|
||||
result.tls_allowInsecure = params.allowinsecure
|
||||
else
|
||||
result.tls_allowInsecure = string.lower(params.allowinsecure) == "true" and "1" or "0"
|
||||
end
|
||||
else
|
||||
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
|
||||
end
|
||||
local insecure = params.allowinsecure or params.insecure or params.allow_insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (allowInsecure_default and "1" or "0")
|
||||
elseif szType == "anytls" then
|
||||
if has_singbox then
|
||||
result.type = 'sing-box'
|
||||
@ -1497,8 +1454,10 @@ local function processData(szType, content, add_mode, group)
|
||||
local host_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
params[t[1]] = UrlDecode(t[2])
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1):lower()] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
-- [2001:4860:4860::8888]:443
|
||||
-- 8.8.8.8:443
|
||||
@ -1514,7 +1473,7 @@ local function processData(szType, content, add_mode, group)
|
||||
result.address = host_port
|
||||
end
|
||||
result.tls = "0"
|
||||
if (not params.security or params.security == "") and params.sni and params.sni ~= "" then
|
||||
if not params.security or params.security == "" then
|
||||
params.security = "tls"
|
||||
end
|
||||
if params.security == "tls" or params.security == "reality" then
|
||||
@ -1532,18 +1491,70 @@ local function processData(szType, content, add_mode, group)
|
||||
end
|
||||
end
|
||||
result.port = port
|
||||
params.allowinsecure = params.allowinsecure or params.insecure
|
||||
if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
|
||||
result.tls_allowInsecure = params.allowinsecure
|
||||
local insecure = params.allowinsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (allowInsecure_default and "1" or "0")
|
||||
end
|
||||
elseif szType == 'naive+https' or szType == 'naive+quic' then
|
||||
if has_singbox then
|
||||
result.type = 'sing-box'
|
||||
result.protocol = "naive"
|
||||
else
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "NaïveProxy", "Sing-Box"))
|
||||
return nil
|
||||
end
|
||||
|
||||
local alias = ""
|
||||
if content:find("#") then
|
||||
local idx_sp = content:find("#")
|
||||
alias = content:sub(idx_sp + 1, -1)
|
||||
content = content:sub(0, idx_sp - 1)
|
||||
end
|
||||
result.remarks = UrlDecode(alias)
|
||||
local Info = content
|
||||
if content:find("@", 1, true) then
|
||||
local contents = split(content, "@")
|
||||
local auth = contents[1] or ""
|
||||
local idx = auth:find(":", 1, true)
|
||||
if not idx then -- Fixed some links that encode the colon between username and password.
|
||||
auth = UrlDecode(auth)
|
||||
idx = auth:find(":", 1, true)
|
||||
end
|
||||
if idx then
|
||||
result.username = UrlDecode(auth:sub(1, idx - 1))
|
||||
result.password = UrlDecode(auth:sub(idx + 1))
|
||||
end
|
||||
Info = (contents[2] or ""):gsub("/%?", "?")
|
||||
end
|
||||
local query = split(Info, "%?")
|
||||
local host_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1)] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
if host_port:find(":") then
|
||||
local sp = split(host_port, ":")
|
||||
result.port = sp[#sp]
|
||||
if api.is_ipv6addrport(host_port) then
|
||||
result.address = api.get_ipv6_only(host_port)
|
||||
else
|
||||
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
|
||||
end
|
||||
local singbox_version = api.get_app_version("sing-box")
|
||||
local version_ge_1_12 = api.compare_versions(singbox_version:match("[^v]+"), ">=", "1.12.0")
|
||||
if not has_singbox or not version_ge_1_12 then
|
||||
log(2, i18n.translatef("Skip the %s node, as %s type nodes require Sing-Box version 1.12 or higher.", result.remarks, szType))
|
||||
return nil
|
||||
result.address = sp[1]
|
||||
end
|
||||
else
|
||||
result.address = host_port
|
||||
end
|
||||
result.tls_serverName = params.sni
|
||||
result.uot = params.uot
|
||||
result.naive_insecure_concurrency = params["insecure-concurrency"] or "0"
|
||||
if params.ech and params.ech ~= "" then
|
||||
result.ech = "1"
|
||||
result.ech_config = params.ech
|
||||
end
|
||||
if szType == "naive+quic" then
|
||||
result.naive_quic = "1"
|
||||
result.naive_congestion_control = params.congestion_control or "bbr"
|
||||
end
|
||||
else
|
||||
log(2, i18n.translatef("%s type node subscriptions are not currently supported, skip this node.", szType))
|
||||
|
||||
@ -48,7 +48,7 @@ eval_set_val() {
|
||||
eval_unset_val() {
|
||||
for i in $@; do
|
||||
for j in $i; do
|
||||
eval unset j
|
||||
eval unset $j
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user