🏅 Sync 2026-10-21 14:22:54

This commit is contained in:
github-actions[bot] committed 2026-10-21 14:22:54 +08:00
1 parent 0b7c0117b8
commit f608112d08
29 files changed
+752 -371

No files matched your search

@@ -928,7 +928,9 @@ local function build_v2ray_mihomo_proxy(sid)
elseif protocol == "snell" then
proxy.type = "snell"
proxy.psk = get_server_field(sid, "snell_psk", "")
proxy.version = number_or_nil(get_server_field(sid, "snell_version", ""))
proxy.version = tonumber(get_server_field(sid, "snell_version", "4")) or 4
proxy.reuse = get_server_field(sid, "snell_reuse", "0") == "1"
proxy.udp = proxy.version >= 3
local obfs_mode = string_or_nil(get_server_field(sid, "snell_obfs", ""))
local obfs_host = string_or_nil(get_server_field(sid, "snell_obfs_host", ""))
if obfs_mode or obfs_host then
@@ -0,0 +1,17 @@
#!/usr/bin/lua
local uci = require("luci.model.uci").cursor()
local json = require "luci.jsonc"
local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section")
local padding = {}
for line in (s.anytls_padding or ""):gmatch("[^\r\n]+") do padding[#padding + 1] = line end
print(json.stringify({
log = {loglevel = "warning"},
inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "anytls",
settings = {users = {{email = "user", password = assert(s.anytls_password)}},
paddingScheme = #padding > 0 and padding or nil},
streamSettings = {network = "raw", security = "tls", tlsSettings = {
certificates = {{oneTimeLoading = true, certificateFile = assert(s.tls_certificateFile), keyFile = assert(s.tls_keyFile)}}
}}
}},
outbounds = {{protocol = "freedom", settings = {}}}
}, 1))
@@ -363,6 +363,34 @@ function outbound:handleIndex(index)
trojan = function()
trojan_shadowsocks()
end,
snell = function()
outbound_settings = {
address = server.server, port = tonumber(server.server_port),
psk = server.snell_psk, version = tonumber(server.snell_version) or 4,
obfs = server.snell_obfs or "", obfsHost = server.snell_obfs_host,
reuse = server.snell_reuse == "1"
}
end,
tuic = function()
local version = tonumber(server.xray_tuic_version) or 5
local alpn = {}
for value in (server.tuic_alpn or ""):gmatch("[^,]+") do alpn[#alpn + 1] = value end
if #alpn == 0 then alpn = {"h3"} end
outbound_settings = {
address = server.server, port = tonumber(server.server_port), version = version,
token = version == 4 and server.xray_tuic_token or nil,
uuid = version == 5 and server.tuic_uuid or nil,
password = version == 5 and server.tuic_passwd or nil,
serverName = server.tls_host, certificateFile = server.xray_tuic_ca,
allowInsecure = server.insecure == "1",
alpn = alpn,
congestionControl = server.congestion_control or "cubic",
udpRelayMode = server.udp_relay_mode or "native",
heartbeatInterval = (tonumber(server.heartbeat) or 10) * 1000,
requestTimeout = (tonumber(server.timeout) or 8) * 1000,
reduceRtt = server.zero_rtt_handshake == "1"
}
end,
shadowsocksr = function()
outbound_settings = {
address = server.server, port = tonumber(server.server_port),
@@ -899,14 +927,53 @@ Xray.outbounds = {
}
}
-- Naive owns TLS/multiplexing; SSR owns obfuscation and uses native UDP.
-- Preserve Xray socket marks and dialer chains for both.
if server.v2ray_protocol == "naive" or server.v2ray_protocol == "shadowsocksr" then
-- These protocols own their framing, obfuscation and multiplexing.
-- Preserve Xray socket marks and dialer chains.
if server.v2ray_protocol == "naive" or server.v2ray_protocol == "shadowsocksr" or server.v2ray_protocol == "tuic" or server.v2ray_protocol == "snell" then
local ob = Xray.outbounds[1]
ob.streamSettings = { network = "raw", sockopt = ob.streamSettings.sockopt }
ob.mux = nil
end
if server.type == "v2ray" and server.transport == "kcptun" then
local supported = {vmess = true, vless = true, trojan = true, shadowsocks = true, socks = true, http = true}
assert(supported[server.v2ray_protocol], "Kcptun requires a supported stream proxy protocol")
assert(server.tls ~= "1" and server.reality ~= "1" and server.xtls ~= "1", "Kcptun cannot be combined with stream TLS or REALITY")
assert(server.kcp_enable ~= "1", "Native Kcptun cannot be combined with the external Kcptun client")
assert(not server.tls_flow or server.tls_flow == "", "Kcptun cannot be combined with XTLS flow")
local options = {}
if server.xray_kcptun_options and server.xray_kcptun_options:match("%S") then
assert(server.xray_kcptun_options:match("^%s*{"), "Kcptun options must be a JSON object")
options = json.parse(server.xray_kcptun_options)
assert(type(options) == "table", "Kcptun options must be a JSON object")
end
options.key = server.xray_kcptun_key
options.crypt = server.xray_kcptun_crypt or "aes"
options.mode = server.xray_kcptun_mode or "fast"
options.smuxver = tonumber(server.xray_kcptun_smuxver) or 1
options.nocomp = server.xray_kcptun_nocomp == "1"
options.conn = tonumber(server.xray_kcptun_conn) or 1
Xray.outbounds[1].streamSettings.kcptunSettings = options
end
if server.type == "v2ray" and server.xray_shadowtls == "1" then
local supported = {vmess = true, vless = true, trojan = true, shadowsocks = true}
assert(supported[server.v2ray_protocol], "ShadowTLS requires a supported TCP proxy protocol")
assert((server.transport or "raw") == "raw" or server.transport == "tcp", "ShadowTLS requires RAW/TCP")
assert(server.tls ~= "1" and server.reality ~= "1", "ShadowTLS cannot be combined with TLS or REALITY")
assert(not server.tls_flow or server.tls_flow == "", "ShadowTLS cannot be combined with XTLS flow")
local stream = Xray.outbounds[1].streamSettings
stream.security = "shadowtls"
stream.shadowtlsSettings = {
version = tonumber(server.xray_shadowtls_version) or 3,
password = server.xray_shadowtls_password,
serverName = server.xray_shadowtls_sni,
fingerprint = server.xray_shadowtls_fingerprint or "chrome",
strictMode = server.xray_shadowtls_strict ~= "0",
allowInsecure = server.xray_shadowtls_insecure == "1"
}
end
if xray_builtin_dns then
table.insert(Xray.outbounds, {
protocol = "dns",
@@ -1322,6 +1389,14 @@ function config:handleIndex(index)
chain_switch[ChainType]()
end
end,
snell = function()
outbound_settings = {
address = server.server, port = tonumber(server.server_port),
psk = server.snell_psk, version = tonumber(server.snell_version) or 4,
obfs = server.snell_obfs or "", obfsHost = server.snell_obfs_host,
reuse = server.snell_reuse == "1"
}
end,
tuic = function()
print(json.stringify(tuic, 1))
end
@@ -0,0 +1,13 @@
#!/usr/bin/lua
local uci = require("luci.model.uci").cursor()
local json = require "luci.jsonc"
local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section")
local version = tonumber(s.snell_version) or 4
print(json.stringify({
log = {loglevel = "warning"},
inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "snell",
settings = {psk = assert(s.snell_psk), version = version,
obfs = s.snell_obfs or "", udp = version >= 3 and s.snell_udp ~= "0"}
}},
outbounds = {{protocol = "freedom", settings = {}}}
}, 1))
@@ -0,0 +1,13 @@
#!/usr/bin/lua
local uci = require("luci.model.uci").cursor()
local json = require "luci.jsonc"
local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section")
print(json.stringify({
log = {loglevel = "warning"},
inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "shadowsocksr",
settings = {password = assert(s.password), method = s.ssr_method or "aes-128-cfb",
protocol = s.ssr_protocol or "auth_aes128_sha1", protocolParam = s.ssr_protocol_param or "",
obfs = s.ssr_obfs or "plain", obfsParam = s.ssr_obfs_param or "", network = "tcp,udp"}
}},
outbounds = {{protocol = "freedom", settings = {}}}
}, 1))
@@ -0,0 +1,19 @@
#!/usr/bin/lua
local uci = require("luci.model.uci").cursor()
local json = require "luci.jsonc"
local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section")
local users, tokens = {}, {}
if s.tuic_uuid and s.tuic_uuid ~= "" then
users[s.tuic_uuid] = assert(s.tuic_password, "TUIC password required")
end
if s.tuic_token and s.tuic_token ~= "" then tokens[1] = s.tuic_token end
assert(next(users) or #tokens > 0, "TUIC credentials required")
print(json.stringify({
log = {loglevel = "warning"},
inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "tuic",
settings = {users = next(users) and users or nil, tokens = #tokens > 0 and tokens or nil,
certificateFile = assert(s.tls_certificateFile), keyFile = assert(s.tls_keyFile)},
streamSettings = {network = "tuic"}
}},
outbounds = {{protocol = "freedom", settings = {}}}
}, 1))
@@ -824,7 +824,9 @@ local function to_mihomo_proxy(node)
elseif node.type == "v2ray" and node.v2ray_protocol == "snell" then
proxy.type = "snell"
proxy.psk = node.snell_psk
proxy.version = tonumber(node.snell_version) or nil
proxy.version = tonumber(node.snell_version) or 4
proxy.udp = proxy.version >= 3
proxy.reuse = node.snell_reuse == "1"
local obfs_mode = string_from_value(node.snell_obfs)
local obfs_host = string_from_value(node.snell_obfs_host)
if obfs_mode or obfs_host then
@@ -1021,8 +1023,8 @@ local function processData(szType, content, cfgid)
result.fast_open = params.tfo
end
elseif szType == "snell" then
if not has_mihomo then
log("跳过 Snell 节点:本地未安装 mihomo。")
if not has_xray and not has_mihomo then
log("跳过 Snell 节点:本地未安装 Xray 或 Mihomo。")
return nil
end
@@ -1041,6 +1043,7 @@ local function processData(szType, content, cfgid)
result.snell_version = first_nonempty(params, {"version", "v"}) or "4"
result.snell_obfs = first_nonempty(params, {"obfs", "obfs-mode", "obfs_mode"})
result.snell_obfs_host = first_nonempty(params, {"obfs-host", "obfs_host", "host"})
result.snell_reuse = (params.reuse == "1" or params.reuse == "true") and "1" or "0"
if not result.snell_psk or result.snell_psk == "" then
result.server = nil
end