2
0
Эх сурвалжийг харах

1.support Hysteria Version 2 full features, remove Hysteria v1 features
2.support tuic full functions for ssr-plus, fixed tuic minor errors and bugs
3.add shadow-tls new features, support full fuctions for ssr-plus

TeF 2 жил өмнө
parent
commit
3d1e9cea63

+ 12 - 2
luci-app-ssr-plus/Makefile

@@ -11,6 +11,7 @@ PKG_CONFIG_DEPENDS:= \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Tuic-Client \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Tuic-Client \
+	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadow-TLS \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
@@ -27,7 +28,7 @@ PKG_CONFIG_DEPENDS:= \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server \
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Trojan
 	CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Trojan
 
 
-LUCI_TITLE:=SS/SSR/V2Ray/Trojan/NaiveProxy/TUIC/Hysteria/Socks5/Tun LuCI interface
+LUCI_TITLE:=SS/SSR/V2Ray/Trojan/NaiveProxy/TUIC/ShadowTLS/Hysteria/Socks5/Tun LuCI interface
 LUCI_PKGARCH:=all
 LUCI_PKGARCH:=all
 LUCI_DEPENDS:= \
 LUCI_DEPENDS:= \
 	@(PACKAGE_libustream-mbedtls||PACKAGE_libustream-openssl||PACKAGE_libustream-wolfssl) \
 	@(PACKAGE_libustream-mbedtls||PACKAGE_libustream-openssl||PACKAGE_libustream-wolfssl) \
@@ -41,6 +42,7 @@ LUCI_DEPENDS:= \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG:chinadns-ng \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG:chinadns-ng \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_TUIC-Client:tuic-client \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_TUIC-Client:tuic-client \
+	+PACKAGE_$(PKG_NAME)_INCLUDE_Shadow-tls:shadow-tls \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks:ipt2socks \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks:ipt2socks \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun:kcptun-client \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun:kcptun-client \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
 	+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
@@ -62,7 +64,7 @@ select PACKAGE_luci-lib-ipkg if PACKAGE_$(PKG_NAME)
 
 
 choice
 choice
 	prompt "Shadowsocks Client Selection"
 	prompt "Shadowsocks Client Selection"
-	default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client if aarch64
+	default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client if aarch64 || x86_64
 	default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client
 	default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client
 
 
 	config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Client
 	config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Client
@@ -127,6 +129,14 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_TUIC-Client
 	depends on !(TARGET_x86_geode||TARGET_x86_legacy)
 	depends on !(TARGET_x86_geode||TARGET_x86_legacy)
 	default n
 	default n
 
 
+config PACKAGE_$(PKG_NAME)_INCLUDE_Shadow-TLS
+	bool "Include shadow-tls"
+	select PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG
+	select PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client
+	depends on aarch64||arm||x86_64
+	depends on !(TARGET_x86_geode||TARGET_x86_legacy)
+	default n
+
 config PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks
 config PACKAGE_$(PKG_NAME)_INCLUDE_IPT2Socks
 	bool "Include IPT2Socks"
 	bool "Include IPT2Socks"
 	default n
 	default n

+ 168 - 37
luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua

@@ -144,8 +144,11 @@ end
 if is_finded("ssr-redir") then
 if is_finded("ssr-redir") then
 	o:value("ssr", translate("ShadowsocksR"))
 	o:value("ssr", translate("ShadowsocksR"))
 end
 end
-if is_finded("sslocal") or is_finded("ss-redir") then
-	o:value("ss", translate("Shadowsocks New Version"))
+if is_finded("ss-local") or is_finded("ss-redir") then
+	o:value("ss", translate("Shadowsocks-libev New Version"))
+end
+if is_finded("sslocal") or is_finded("ssmanager") then
+	o:value("ss_rust", translate("Shadowsocks-rust Version"))
 end
 end
 if is_finded("trojan") then
 if is_finded("trojan") then
 	o:value("trojan", translate("Trojan"))
 	o:value("trojan", translate("Trojan"))
@@ -159,6 +162,9 @@ end
 if is_finded("tuic-client") then
 if is_finded("tuic-client") then
 	o:value("tuic", translate("TUIC"))
 	o:value("tuic", translate("TUIC"))
 end
 end
+if is_finded("shadow-tls") and is_finded("sslocal") then
+	o:value("shadowtls", translate("Shadow-TLS"))
+end
 if is_finded("ipt2socks") then
 if is_finded("ipt2socks") then
 	o:value("socks5", translate("Socks5"))
 	o:value("socks5", translate("Socks5"))
 end
 end
@@ -196,23 +202,27 @@ o.datatype = "host"
 o.rmempty = false
 o.rmempty = false
 o:depends("type", "ssr")
 o:depends("type", "ssr")
 o:depends("type", "ss")
 o:depends("type", "ss")
+o:depends("type", "ss_rust")
 o:depends("type", "v2ray")
 o:depends("type", "v2ray")
 o:depends("type", "trojan")
 o:depends("type", "trojan")
 o:depends("type", "naiveproxy")
 o:depends("type", "naiveproxy")
 o:depends("type", "hysteria")
 o:depends("type", "hysteria")
 o:depends("type", "tuic")
 o:depends("type", "tuic")
+o:depends("type", "shadowtls")
 o:depends("type", "socks5")
 o:depends("type", "socks5")
 
 
 o = s:option(Value, "server_port", translate("Server Port"))
 o = s:option(Value, "server_port", translate("Server Port"))
 o.datatype = "port"
 o.datatype = "port"
-o.rmempty = ({port_hopping=0 and false or true})
+o.rmempty = true
 o:depends("type", "ssr")
 o:depends("type", "ssr")
 o:depends("type", "ss")
 o:depends("type", "ss")
+o:depends("type", "ss_rust")
 o:depends("type", "v2ray")
 o:depends("type", "v2ray")
 o:depends("type", "trojan")
 o:depends("type", "trojan")
 o:depends("type", "naiveproxy")
 o:depends("type", "naiveproxy")
-o:depends({type="hysteria",port_hopping=0})
+o:depends({type = "hysteria",port_hopping = 0})
 o:depends("type", "tuic")
 o:depends("type", "tuic")
+o:depends("type", "shadowtls")
 o:depends("type", "socks5")
 o:depends("type", "socks5")
 
 
 o = s:option(Flag, "auth_enable", translate("Enable Authentication"))
 o = s:option(Flag, "auth_enable", translate("Enable Authentication"))
@@ -234,8 +244,10 @@ o.password = true
 o.rmempty = true
 o.rmempty = true
 o:depends("type", "ssr")
 o:depends("type", "ssr")
 o:depends("type", "ss")
 o:depends("type", "ss")
+o:depends("type", "ss_rust")
 o:depends("type", "trojan")
 o:depends("type", "trojan")
 o:depends("type", "naiveproxy")
 o:depends("type", "naiveproxy")
+o:depends("type", "shadowtls")
 o:depends({type = "socks5", auth_enable = true})
 o:depends({type = "socks5", auth_enable = true})
 o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true})
 o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true})
 o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", auth_enable = true})
 o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", auth_enable = true})
@@ -255,6 +267,7 @@ for _, v in ipairs(encrypt_methods_ss) do
 end
 end
 o.rmempty = true
 o.rmempty = true
 o:depends("type", "ss")
 o:depends("type", "ss")
+o:depends("type", "ss_rust")
 o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
 o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
 
 
 o = s:option(Flag, "uot", translate("UDP over TCP"))
 o = s:option(Flag, "uot", translate("UDP over TCP"))
@@ -282,10 +295,12 @@ if is_finded("xray-plugin") then
 end
 end
 o.rmempty = true
 o.rmempty = true
 o:depends("type", "ss")
 o:depends("type", "ss")
+o:depends("type", "ss_rust")
 
 
 o = s:option(Value, "plugin_opts", translate("Plugin Opts"))
 o = s:option(Value, "plugin_opts", translate("Plugin Opts"))
 o.rmempty = true
 o.rmempty = true
 o:depends("type", "ss")
 o:depends("type", "ss")
+o:depends("type", "ss_rust")
 
 
 o = s:option(ListValue, "protocol", translate("Protocol"))
 o = s:option(ListValue, "protocol", translate("Protocol"))
 for _, v in ipairs(protocol) do
 for _, v in ipairs(protocol) do
@@ -307,55 +322,162 @@ o:depends("type", "ssr")
 o = s:option(Value, "obfs_param", translate("Obfs param (optional)"))
 o = s:option(Value, "obfs_param", translate("Obfs param (optional)"))
 o:depends("type", "ssr")
 o:depends("type", "ssr")
 
 
--- [[ Hysteria ]]--
-o = s:option(Flag, "port_hopping", translate("Enable Port Hopping"))
+
+-- [[ Hysteria2 ]]--
+o = s:option(Value, "hy2_auth", translate("Users Authentication"))
+o:depends("type", "hysteria")
+o.rmempty = false
+
+o = s:option(ListValue, "hysteria_protocol", translate("Protocol"))
+o:depends("type", "hysteria")
+o:value("udp", translate("udp"))
+o.default = "udp"
+o.rmempty = true
+
+o = s:option(Flag, "port_hopping", translate("Port Hopping"))
 o:depends("type", "hysteria")
 o:depends("type", "hysteria")
 o.rmempty = true
 o.rmempty = true
 o.default = "0"
 o.default = "0"
 
 
-o = s:option(Value, "port_range", translate("Port Range"))
-o:depends({type = "hysteria", port_hopping = "1"})
-o.datatype = "portrange"
+o = s:option(Value, "port_range", translate("Port range"))
+o:depends({type = "hysteria", port_hopping = 1})
+o.rmempty = false
+
+o = s:option(Flag, "lazy_mode", translate("Enable Lazy Mode"))
+o:depends("type", "hysteria")
 o.rmempty = true
 o.rmempty = true
+o.default = "0"
 
 
-o = s:option(ListValue, "hysteria_protocol", translate("Protocol"))
+o = s:option(Flag, "flag_obfs", translate("Enable Obfuscation"))
 o:depends("type", "hysteria")
 o:depends("type", "hysteria")
-o:value("udp", translate("udp"))
-o:value("wechat-video", translate("wechat-video"))
-o:value("faketcp", translate("faketcp"))
-o.default = "udp"
 o.rmempty = true
 o.rmempty = true
+o.default = "0"
+
+o = s:option(Value, "obfs_type", translate("Obfuscation Type"))
+o:depends({type = "hysteria", flag_obfs = "1"})
+o.rmempty = true
+o.default = "salamander"
+
+o = s:option(Value, "salamander", translate("Obfuscation Password"))
+o:depends({type = "hysteria", flag_obfs = "1"})
+o.rmempty = true
+o.default = "cry_me_a_r1ver"
 
 
-o = s:option(ListValue, "auth_type", translate("Authentication type"))
+o = s:option(Flag, "flag_quicparam", translate("Hysterir QUIC parameters"))
 o:depends("type", "hysteria")
 o:depends("type", "hysteria")
-o:value("0", translate("disabled"))
-o:value("1", translate("base64"))
-o:value("2", translate("string"))
 o.rmempty = true
 o.rmempty = true
+o.default = "0"
 
 
-o = s:option(Value, "auth_payload", translate("Authentication payload"))
-o:depends({type = "hysteria", auth_type = "1"})
-o:depends({type = "hysteria", auth_type = "2"})
+--[[Hysteria2 QUIC parameters setting]]
+o = s:option(Value, "initstreamreceivewindow", translate("QUIC initStreamReceiveWindow"))
+o:depends({type = "hysteria",flag_quicparam = "1"})
+o.datatype = "uinteger"
 o.rmempty = true
 o.rmempty = true
+o.default = "8388608"
 
 
-o = s:option(Value, "recv_window", translate("QUIC connection receive window"))
+o = s:option(Value, "maxstreamseceivewindow", translate("QUIC maxStreamReceiveWindow"))
+o:depends({type = "hysteria",flag_quicparam = "1"})
 o.datatype = "uinteger"
 o.datatype = "uinteger"
-o:depends("type", "hysteria")
 o.rmempty = true
 o.rmempty = true
+o.default = "8388608"
 
 
-o = s:option(Value, "recv_window_conn", translate("QUIC stream receive window"))
+o = s:option(Value, "initconnreceivewindow", translate("QUIC initConnReceiveWindow"))
+o:depends({type = "hysteria",flag_quicparam = "1"})
 o.datatype = "uinteger"
 o.datatype = "uinteger"
-o:depends("type", "hysteria")
 o.rmempty = true
 o.rmempty = true
+o.default = "20971520"
 
 
-o = s:option(Flag, "disable_mtu_discovery", translate("Disable Path MTU discovery"))
-o:depends("type", "hysteria")
+o = s:option(Value, "maxconnreceivewindow", translate("QUIC maxConnReceiveWindow"))
+o:depends({type = "hysteria",flag_quicparam = "1"})
+o.datatype = "uinteger"
 o.rmempty = true
 o.rmempty = true
+o.default = "20971520"
 
 
-o = s:option(Flag, "lazy_start", translate("Lazy Start"))
-o:depends("type", "hysteria")
+o = s:option(Value, "maxincomingstreams", translate("QUIC maxIncomingStreams"))
+o:depends({type = "hysteria",flag_quicparam = "1"})
+o.datatype = "uinteger"
+o.rmempty = true
+o.default = "1024"
+
+o = s:option(Value, "maxidletimeout", translate("QUIC maxIdleTimeout(Unit:second)"))
+o:depends({type = "hysteria",flag_quicparam = "1"})
+o.rmempty = true
+o.default = "30s"
+
+o = s:option(Value, "keepaliveperiod", translate("The keep-alive period.(Unit:second)"))
+o:depends({type = "hysteria",flag_quicparam = "1"})
+o.rmempty = true
+o.default = "10s"
+
+o = s:option(Flag, "disablepathmtudiscovery", translate("Disable Path MTU discovery"))
+o:depends({type = "hysteria",flag_quicparam = "1"})
 o.rmempty = true
 o.rmempty = true
+o.default = false
+
+
+--[[ Shadow-TLS Options ]]
+o = s:option(ListValue, "shadowtls_protocol", translate("shadowTLS protocol Version"))
+o:depends("type", "shadowtls")
+o:value("v3", translate("Enable V3 protocol."))
+o:value("v2", translate("Enable V2 protocol."))
+o.default = "v3"
+o.rmempty = true
+
+o = s:option(Flag, "strict", translate("TLS 1.3 Strict mode"))
+o:depends("type", "shadowtls")
+o.default = "1"
+o.rmempty = false
+
+o = s:option(Flag, "fastopen", translate("TCP Fast Open"))
+o:depends("type", "shadowtls")
+o.default = "0"
+o.rmempty = false
+
+o = s:option(Flag, "disable_nodelay", translate("Disable TCP No_delay"))
+o:depends("type", "shadowtls")
 o.default = "0"
 o.default = "0"
+o.rmempty = true
+
+o = s:option(Value, "shadowtls_sni", translate("shadow-TLS SNI"))
+o:depends("type", "shadowtls")
+o.datatype = "host"
+o.rmempty = true
+o.default = ""
+
+--[[ add a ListValue for Choose chain type,sslocal or vmess ]]
+o = s:option(ListValue, "chain_type", translate("Shadow-TLS ChainPoxy type"))
+o:depends("type", "shadowtls")
+if is_finded("sslocal") then
+	o:value("sslocal", translate("Shadowsocks-rust Version"))
+end
+if is_finded("xray") or is_finded("v2ray") then
+	o:value("vmess", translate("Vmess Protocol"))
+end
+o.default = "sslocal"
+o.rmempty = false
+
+o = s:option(Value, "sslocal_password",translate("Shadowsocks password"))
+o:depends({type = "shadowtls", chain_type = "sslocal"})
+o.rmempty = true
+
+o = s:option(ListValue, "sslocal_method", translate("Encrypt Method"))
+o:depends({type = "shadowtls", chain_type = "sslocal"})
+for _, v in ipairs(encrypt_methods_ss) do
+	o:value(v)
+end
+
+o = s:option(Value, "vmess_uuid", translate("Vmess UUID"))
+o:depends({type = "shadowtls", chain_type = "vmess"})
+o.rmempty = false
+o.default = uuid
+
+o = s:option(ListValue, "vmess_method", translate("Encrypt Method"))
+o:depends({type = "shadowtls", chain_type = "vmess"})
+for _, v in ipairs(securitys) do
+	o:value(v, v:lower())
+end
+o.rmempty = true
+o.default="auto"
 
 
 -- [[ TUIC ]]
 -- [[ TUIC ]]
 -- TuicNameId
 -- TuicNameId
@@ -420,29 +542,29 @@ o.rmempty = true
 o = s:option(Value, "send_window", translate("TUIC send window"))
 o = s:option(Value, "send_window", translate("TUIC send window"))
 o:depends("type", "tuic")
 o:depends("type", "tuic")
 o.datatype = "uinteger"
 o.datatype = "uinteger"
-o.default = 16777216
+o.default = 20971520
 o.rmempty = true
 o.rmempty = true
 
 
 o = s:option(Value, "receive_window", translate("TUIC receive window"))
 o = s:option(Value, "receive_window", translate("TUIC receive window"))
 o:depends("type", "tuic")
 o:depends("type", "tuic")
 o.datatype = "uinteger"
 o.datatype = "uinteger"
-o.default = 8388608
+o.default = 10485760
 o.rmempty = true
 o.rmempty = true
 
 
 o = s:option(Flag, "disable_sni", translate("Disable SNI"))
 o = s:option(Flag, "disable_sni", translate("Disable SNI"))
 o:depends("type", "tuic")
 o:depends("type", "tuic")
-o.default = 0
+o.default = "0"
 o.rmempty = true
 o.rmempty = true
 
 
 o = s:option(Flag, "zero_rtt_handshake", translate("Enable 0-RTT QUIC handshake"))
 o = s:option(Flag, "zero_rtt_handshake", translate("Enable 0-RTT QUIC handshake"))
 o:depends("type", "tuic")
 o:depends("type", "tuic")
-o.default = 0
+o.default = "0"
 o.rmempty = true
 o.rmempty = true
 
 
---Tuic settings for the local inbound socks5 server
-o = s:option(Flag, "tuic_dual_stack", translate("Set if the listening socket should be dual-stack"))
+-- Tuic settings for the local inbound socks5 server
+o = s:option(Flag, "tuic_dual_stack", translate("Dual-stack Listening Socket"))
 o:depends("type", "tuic")
 o:depends("type", "tuic")
-o.default = 0
+o.default = "0"
 o.rmempty = true
 o.rmempty = true
 
 
 o = s:option(Value, "tuic_max_package_size", translate("Maximum packet size the socks5 server can receive from external"))
 o = s:option(Value, "tuic_max_package_size", translate("Maximum packet size the socks5 server can receive from external"))
@@ -679,7 +801,6 @@ o.rmempty = true
 
 
 o = s:option(Value, "seed", translate("Obfuscate password (optional)"))
 o = s:option(Value, "seed", translate("Obfuscate password (optional)"))
 o:depends("transport", "kcp")
 o:depends("transport", "kcp")
-o:depends("type", "hysteria")
 o.rmempty = true
 o.rmempty = true
 
 
 o = s:option(Flag, "congestion", translate("Congestion"))
 o = s:option(Flag, "congestion", translate("Congestion"))
@@ -791,6 +912,11 @@ o:depends("tls", true)
 o:depends("type", "hysteria")
 o:depends("type", "hysteria")
 o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
 o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
 
 
+-- [[ Hysteria2 TLS pinSHA256 ]] --
+o = s:option(Value, "pinsha256", translate("Certificate fingerprint"))
+o:depends({type ="hysteria", insecure = true })
+o.rmempty = true
+
 -- [[ Mux ]]--
 -- [[ Mux ]]--
 o = s:option(Flag, "mux", translate("Mux"))
 o = s:option(Flag, "mux", translate("Mux"))
 o.rmempty = false
 o.rmempty = false
@@ -864,6 +990,7 @@ o.rmempty = true
 o.default = "0"
 o.default = "0"
 o:depends("type", "ssr")
 o:depends("type", "ssr")
 o:depends("type", "ss")
 o:depends("type", "ss")
+o:depends("type", "ss_rust")
 o:depends("type", "trojan")
 o:depends("type", "trojan")
 o:depends("type", "hysteria")
 o:depends("type", "hysteria")
 
 
@@ -882,22 +1009,26 @@ if is_finded("kcptun-client") then
 	o.default = "0"
 	o.default = "0"
 	o:depends("type", "ssr")
 	o:depends("type", "ssr")
 	o:depends("type", "ss")
 	o:depends("type", "ss")
+	o:depends("type", "ss_rust")
 
 
 	o = s:option(Value, "kcp_port", translate("KcpTun Port"))
 	o = s:option(Value, "kcp_port", translate("KcpTun Port"))
 	o.datatype = "port"
 	o.datatype = "port"
 	o.default = 4000
 	o.default = 4000
 	o:depends("type", "ssr")
 	o:depends("type", "ssr")
 	o:depends("type", "ss")
 	o:depends("type", "ss")
+	o:depends("type", "ss_rust")
 
 
 	o = s:option(Value, "kcp_password", translate("KcpTun Password"))
 	o = s:option(Value, "kcp_password", translate("KcpTun Password"))
 	o.password = true
 	o.password = true
 	o:depends("type", "ssr")
 	o:depends("type", "ssr")
 	o:depends("type", "ss")
 	o:depends("type", "ss")
+	o:depends("type", "ss_rust")
 
 
 	o = s:option(Value, "kcp_param", translate("KcpTun Param"))
 	o = s:option(Value, "kcp_param", translate("KcpTun Param"))
 	o.default = "--nocomp"
 	o.default = "--nocomp"
 	o:depends("type", "ssr")
 	o:depends("type", "ssr")
 	o:depends("type", "ss")
 	o:depends("type", "ss")
+	o:depends("type", "ss_rust")
 end
 end
 
 
 return m
 return m

+ 67 - 2
luci-app-ssr-plus/po/zh-cn/ssr-plus.po

@@ -106,14 +106,78 @@ msgstr "混淆参数(可选)"
 msgid "Authentication type"
 msgid "Authentication type"
 msgstr "验证类型"
 msgstr "验证类型"
 
 
+msgid "Users Authentication"
+msgstr "用户验证"
+
+msgid "NOTE: If the server uses the userpass authentication, the format must be username:password."
+msgstr "注意: 如果服务器使用 userpass 验证,格式必须是 username:password。"
+
 msgid "Enable Port Hopping"
 msgid "Enable Port Hopping"
 msgstr "启用端口跃迁"
 msgstr "启用端口跃迁"
 
 
 msgid "Port Range"
 msgid "Port Range"
 msgstr "端口范围值"
 msgstr "端口范围值"
 
 
-msgid "Authentication payload"
-msgstr "验证载荷"
+msgid "Enable Lazy Mode"
+msgstr "启用懒狗模式"
+
+msgid "Enable Obfuscation"
+msgstr "启用混淆功能"
+
+msgid "Obfuscation Type"
+msgstr "混淆类型"
+
+msgid "Obfuscation Password"
+msgstr "混淆密码"
+
+msgid "Hysterir QUIC parameters"
+msgstr "QUIC参数"
+
+msgid "QUIC initStreamReceiveWindow"
+msgstr "QUIC初始流接收窗口大小。"
+
+msgid "QUIC maxStreamReceiveWindow"
+msgstr "QUIC最大的流接收窗口大小"
+
+msgid "QUIC initConnReceiveWindow"
+msgstr "QUIC初始的连接接收窗口大小"
+
+msgid "QUIC maxConnReceiveWindow"
+msgstr "QUIC最大的连接接收窗口大小"
+
+msgid "QUIC maxIdleTimeout(Unit:second)"
+msgstr "QUIC最长空闲超时时间(单位:秒)"
+
+msgid "The keep-alive period.(Unit:second)"
+msgstr "心跳包发送间隔(单位:秒)"
+
+
+msgid "Certificate fingerprint"
+msgstr "证书指纹"
+
+msgid "shadowTLS protocol Version"
+msgstr "ShadowTLS协议版本"
+
+msgid "TLS 1.3 Strict mode"
+msgstr "TLS 1.3 限定模式"
+
+msgid "Disable TCP No_delay"
+msgstr "禁用TCP无延迟"
+
+msgid "shadow-TLS SNI"
+msgstr "服务器名称指示"
+
+msgid "Shadow-TLS ChainPoxy type"
+msgstr "代理链类型"
+
+msgid "Shadowsocks-rust Version"
+msgstr "shadowsocks rust版本"
+
+msgid "Vmess Protocol"
+msgstr "VMESS协议"
+
+msgid "Shadowsocks password"
+msgstr "shadowsocks密码"
 
 
 msgid "QUIC connection receive window"
 msgid "QUIC connection receive window"
 msgstr "QUIC 连接接收窗口"
 msgstr "QUIC 连接接收窗口"
@@ -121,6 +185,7 @@ msgstr "QUIC 连接接收窗口"
 msgid "QUIC stream receive window"
 msgid "QUIC stream receive window"
 msgstr "QUIC 流接收窗口"
 msgstr "QUIC 流接收窗口"
 
 
+
 msgid "Lazy Start"
 msgid "Lazy Start"
 msgstr "延迟启动"
 msgstr "延迟启动"
 
 

+ 177 - 61
luci-app-ssr-plus/root/etc/init.d/shadowsocksr

@@ -18,13 +18,17 @@ LOG_FILE=/var/log/ssrplus.log
 TMP_PATH=/var/etc/ssrplus
 TMP_PATH=/var/etc/ssrplus
 TMP_BIN_PATH=$TMP_PATH/bin
 TMP_BIN_PATH=$TMP_PATH/bin
 TMP_DNSMASQ_PATH=/tmp/dnsmasq.d/dnsmasq-ssrplus.d
 TMP_DNSMASQ_PATH=/tmp/dnsmasq.d/dnsmasq-ssrplus.d
+
+chain_config_file=		   #generate shadowtls chain proxy config file
 tcp_config_file=
 tcp_config_file=
 udp_config_file=
 udp_config_file=
 shunt_config_file=
 shunt_config_file=
 local_config_file=
 local_config_file=
 shunt_dns_config_file=
 shunt_dns_config_file=
 tmp_local_port=
 tmp_local_port=
+
 ARG_UDP=
 ARG_UDP=
+
 dns_port="5335"            #dns port
 dns_port="5335"            #dns port
 china_dns_port="5333"      #china_dns_port
 china_dns_port="5333"      #china_dns_port
 tmp_dns_port="300"         #dns2socks temporary port
 tmp_dns_port="300"         #dns2socks temporary port
@@ -34,6 +38,7 @@ tmp_shunt_port="303"       #shunt temporary port
 tmp_shunt_local_port="304" #shunt socks temporary port
 tmp_shunt_local_port="304" #shunt socks temporary port
 tmp_shunt_dns_port="305"   #shunt dns2socks temporary port
 tmp_shunt_dns_port="305"   #shunt dns2socks temporary port
 tmp_tcp_local_port="306"   #tcp socks temporary port
 tmp_tcp_local_port="306"   #tcp socks temporary port
+
 server_count=0
 server_count=0
 redir_tcp=0
 redir_tcp=0
 redir_udp=0
 redir_udp=0
@@ -217,60 +222,67 @@ start_dns() {
 	fi
 	fi
 }
 }
 
 
-gen_service_file() {
+gen_service_file() { #1-server.type 2-cfgname 3-file_path
+	local fastopen
 	if [ $(uci_get_by_name $2 fast_open) == "1" ]; then
 	if [ $(uci_get_by_name $2 fast_open) == "1" ]; then
-		local fastopen="true"
+		fastopen="true"
 	else
 	else
-		local fastopen="false"
+		fastopen="false"
 	fi
 	fi
-	if [ $1 == "ssr" ]; then
+	case $1 in
+		ssr)
 		cat <<-EOF >$3
 		cat <<-EOF >$3
 			{
 			{
-			  "server": "0.0.0.0",
-			  "server_ipv6": "::",
-			  "server_port": $(uci_get_by_name $2 server_port),
-			  "mode": "tcp_and_udp",
-			  "password": "$(uci_get_by_name $2 password)",
-			  "timeout": $(uci_get_by_name $2 timeout 60),
-			  "method": "$(uci_get_by_name $2 encrypt_method)",
-			  "protocol": "$(uci_get_by_name $2 protocol)",
-			  "protocol_param": "$(uci_get_by_name $2 protocol_param)",
-			  "obfs": "$(uci_get_by_name $2 obfs)",
-			  "obfs_param": "$(uci_get_by_name $2 obfs_param)",
-			  "fast_open": $fastopen
+				"server": "0.0.0.0",
+				"server_ipv6": "::",
+				"server_port": $(uci_get_by_name $2 server_port),
+				"mode": "tcp_and_udp",
+				"password": "$(uci_get_by_name $2 password)",
+				"timeout": $(uci_get_by_name $2 timeout 60),
+				"method": "$(uci_get_by_name $2 encrypt_method)",
+				"protocol": "$(uci_get_by_name $2 protocol)",
+				"protocol_param": "$(uci_get_by_name $2 protocol_param)",
+				"obfs": "$(uci_get_by_name $2 obfs)",
+				"obfs_param": "$(uci_get_by_name $2 obfs_param)",
+				"fast_open": $fastopen
 			}
 			}
-		EOF
-	else
-		cat <<-EOF >$3
-			{
-			  "server": "0.0.0.0",
-			  "server_ipv6": "::",
-			  "server_port": $(uci_get_by_name $2 server_port),
-			  "mode": "tcp_and_udp",
-			  "password": "$(uci_get_by_name $2 password)",
-			  "timeout": $(uci_get_by_name $2 timeout 60),
-			  "method": "$(uci_get_by_name $2 encrypt_method_ss)",
-			  "protocol": "socks",
-			  "fast_open": $fastopen
-			}
-		EOF
-	fi
+			EOF
+		;;
+		ss)
+			cat <<-EOF >$3
+				{
+					"server": "0.0.0.0",
+					"server_ipv6": "::",
+					"server_port": $(uci_get_by_name $2 server_port),
+					"mode": "tcp_and_udp",
+					"password": "$(uci_get_by_name $2 password)",
+					"timeout": $(uci_get_by_name $2 timeout 60),
+					"method": "$(uci_get_by_name $2 encrypt_method_ss)",
+					"protocol": "socks",
+					"fast_open": $fastopen
+				}
+			EOF
+		;;
+	esac
 }
 }
 
 
 get_name() {
 get_name() {
 	case "$1" in
 	case "$1" in
 	ss) echo "Shadowsocks" ;;
 	ss) echo "Shadowsocks" ;;
 	ssr) echo "ShadowsocksR" ;;
 	ssr) echo "ShadowsocksR" ;;
+	ss_rust) echo "Shadowsocks-Rust";;
 	esac
 	esac
 }
 }
 
 
-gen_config_file() { #server1 type2 code3 local_port4 socks_port5 threads5
+gen_config_file() { #server1 type2 code3 local_port4 socks_port5 chain6 threads5
 	case "$3" in
 	case "$3" in
 	1)
 	1)
 		config_file=$tcp_config_file
 		config_file=$tcp_config_file
+		chain_config_file=$(echo ${config_file}|sed 's/ssrplus\//ssrplus\/chain-/')
 		;;
 		;;
 	2)
 	2)
 		config_file=$udp_config_file
 		config_file=$udp_config_file
+		chain_config_file=$(echo ${config_file}|sed 's/ssrplus\//ssrplus\/chain-/')
 		;;
 		;;
 	3)
 	3)
 		if [ -n "$tmp_local_port" ]; then
 		if [ -n "$tmp_local_port" ]; then
@@ -279,14 +291,16 @@ gen_config_file() { #server1 type2 code3 local_port4 socks_port5 threads5
 			local tmp_port=$tmp_shunt_local_port
 			local tmp_port=$tmp_shunt_local_port
 		fi
 		fi
 		config_file=$shunt_config_file
 		config_file=$shunt_config_file
+		chain_config_file=$(echo ${config_file}|sed 's/ssrplus\//ssrplus\/chain-/')
 		;;
 		;;
 	4)
 	4)
 		local ss_protocol="socks"
 		local ss_protocol="socks"
 		config_file=$local_config_file
 		config_file=$local_config_file
+		chain_config_file=$(echo ${config_file}|sed 's/ssrplus\//ssrplus\/chain-/')
 		;;
 		;;
 	esac
 	esac
 	case "$2" in
 	case "$2" in
-	ss | ssr)
+	ss | ssr | ss_rust)
 		lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 ${ss_protocol:-redir} >$config_file
 		lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 ${ss_protocol:-redir} >$config_file
 		if [ "$3" == "3" ]; then
 		if [ "$3" == "3" ]; then
 			lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $tmp_port socks >$shunt_dns_config_file
 			lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $tmp_port socks >$shunt_dns_config_file
@@ -330,7 +344,25 @@ gen_config_file() { #server1 type2 code3 local_port4 socks_port5 threads5
 		lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 $5 >$config_file
 		lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 $5 >$config_file
 		;;
 		;;
 	tuic)
 	tuic)
-		lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 >$config_file
+		case "$3" in
+		1|2|4)
+			lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 >$config_file
+			;;
+		3)
+			[ -z "$6" ] && lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 >$shunt_dns_config_file || lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 >$config_file
+			;;
+		esac
+		;;
+	shadowtls)
+		case "$3" in
+			1|2|4)
+        [ -z "$6" ] && lua /usr/share/shadowsocksr/gen_config.lua $1 $type $4 >$chain_config_file || lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 $5 $6 >$config_file
+        ;;
+			3)
+				lua /usr/share/shadowsocksr/gen_config.lua $1 $type $4 >$chain_config_file
+				lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 $5 $6 >$config_file
+				;;
+		esac
 		;;
 		;;
 	socks5)
 	socks5)
 		/usr/share/shadowsocksr/genred2config.sh $config_file $2 $mode $4 \
 		/usr/share/shadowsocksr/genred2config.sh $config_file $2 $mode $4 \
@@ -344,7 +376,7 @@ gen_config_file() { #server1 type2 code3 local_port4 socks_port5 threads5
 		/usr/share/shadowsocksr/genred2config.sh $config_file $2 $(uci_get_by_name $1 iface "br-lan") $4
 		/usr/share/shadowsocksr/genred2config.sh $config_file $2 $(uci_get_by_name $1 iface "br-lan") $4
 		;;
 		;;
 	esac
 	esac
-	sed -i 's/\\//g' $TMP_PATH/*-ssr-*.json
+	sed -i 's/\\//g' $TMP_PATH/*-ssr-*.json #>/dev/null > 2>&1
 }
 }
 
 
 start_udp() {
 start_udp() {
@@ -376,17 +408,34 @@ start_udp() {
 	hysteria)
 	hysteria)
 		gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
 		gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
 		ln_start_bin $(first_type hysteria) hysteria client --config $udp_config_file
 		ln_start_bin $(first_type hysteria) hysteria client --config $udp_config_file
-		echolog "UDP TPROXY Relay:$($(first_type "hysteria") --version | awk '{print $1,$3}') Started!"
+		echolog "UDP TPROXY Relay:$($(first_type "hysteria") version | awk '{print $1,$3}') Started!"
 		;;
 		;;
 	tuic)
 	tuic)
-		# gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_local_port
-		# ln_start_bin $(first_type tuic-client) tuic-client --config $udp_config_file
-		# ln_start_bin $(first_type ipt2socks) ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_udp_local_port -l $tmp_udp_port
-		# echolog "UDP TPROXY Relay:tuic-client $($(first_type tuic-client) --version) Started!"
 		# FIXME: ipt2socks cannot handle udp reply from tuic
 		# FIXME: ipt2socks cannot handle udp reply from tuic
+		# 20230726 uncomment following 4 lines
+		gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_local_port
+		ln_start_bin $(first_type tuic-client) tuic-client --config $udp_config_file
+		ln_start_bin $(first_type ipt2socks) ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_udp_local_port -l $tmp_udp_port
+		echolog "UDP TPROXY Relay:tuic-client $($(first_type tuic-client) --version) Started!"
 		echolog "TUIC UDP TPROXY Relay not supported!"
 		echolog "TUIC UDP TPROXY Relay not supported!"
-		redir_udp=0
-		ARG_UDP=""
+		#redir_udp=0
+		#ARG_UDP=""
+		;;
+	shadowtls)
+		gen_config_file $UDP_RELAY_SERVER $type 2 ${tmp_udp_local_port}
+		gen_config_file $UDP_RELAY_SERVER $type 2 ${tmp_udp_local_port} 0 chain
+		ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_config_file
+		local chain_type=$(uci_get_by_name $UDP_RELAY_SERVER chain_type)
+		case ${chain_type} in
+			vmess)
+				ln_start_bin $(first_type xray v2ray) v2ray run -c $udp_config_file
+				echolog "UDP TPROXY Relay:shadow-tls chain-to $($(first_type xray) --version) Started!"
+				;;
+			sslocal)
+				ln_start_bin $(first_type sslocal) sslocal -c $udp_config_file
+				echolog "UDP TPROXY Relay:shadow-tls chain-to $($(first_type sslocal) --version) Started!"
+				;;
+		esac
 		;;
 		;;
 	socks5)
 	socks5)
 		# if [ "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0)" == "1" ]; then
 		# if [ "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0)" == "1" ]; then
@@ -408,7 +457,7 @@ start_udp() {
 start_shunt() {
 start_shunt() {
 	local type=$(uci_get_by_name $SHUNT_SERVER type)
 	local type=$(uci_get_by_name $SHUNT_SERVER type)
 	case "$type" in
 	case "$type" in
-	ss | ssr)
+	ss | ssr |ss_rust)
 		gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port
 		gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port
 		ss_program="$(first_type ${type}local ${type}-redir)"
 		ss_program="$(first_type ${type}local ${type}-redir)"
 		ln_start_bin $ss_program ${type}-redir -c $shunt_config_file
 		ln_start_bin $ss_program ${type}-redir -c $shunt_config_file
@@ -463,21 +512,39 @@ start_shunt() {
 		fi
 		fi
 		ln_start_bin $(first_type hysteria) hysteria client --config $shunt_config_file
 		ln_start_bin $(first_type hysteria) hysteria client --config $shunt_config_file
 		ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_port 8.8.8.8:53 127.0.0.1:$tmp_shunt_dns_port -q
 		ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_port 8.8.8.8:53 127.0.0.1:$tmp_shunt_dns_port -q
-		echolog "shunt:$($(first_type hysteria) --version | awk '{print $1,$3}') Started!"
+		echolog "shunt:$($(first_type hysteria) version | awk '{print $1,$3}') Started!"
 		;;
 		;;
 	tuic)
 	tuic)
-		if [ -n "$tmp_local_port" ]; then
-			local tmp_port=$tmp_local_port
-		else
-			local tmp_port=$tmp_shunt_local_port
-			gen_config_file $SHUNT_SERVER $type 3 $tmp_port
-			ln_start_bin $(first_type tuic-client) tuic-client --config $shunt_config_file
-		fi
-		ln_start_bin $(first_type ipt2socks) ipt2socks -R -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_port -l $tmp_shunt_port
+		local chain_shunt_port="30${tmp_shunt_port}"
+		gen_config_file $SHUNT_SERVER $type 3 $chain_shunt_port 0 chain #make a tuic socks:30303, make a ipt2socks redir:303
+		ln_start_bin $(first_type tuic-client) tuic-client --config $shunt_config_file
+		ln_start_bin $(first_type ipt2socks) ipt2socks -R -b 0.0.0.0 -4 -s 127.0.0.1 -p $chain_shunt_port -l $tmp_shunt_port
+
+		[ -n "$tmp_local_port" ] && tmp_port=$tmp_local_port || tmp_port=$tmp_shunt_local_port
+		gen_config_file $SHUNT_SERVER $type 3 $tmp_port		# make a tuic socks :304
+		ln_start_bin $(first_type tuic-client) tuic-client --config $shunt_dns_config_file
 		ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_port 8.8.8.8:53 127.0.0.1:$tmp_shunt_dns_port -q
 		ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_port 8.8.8.8:53 127.0.0.1:$tmp_shunt_dns_port -q
-		echolog "shunt:tuic-client $($(first_type tuic-client) --version) Started!"
+		echolog "Netflix Separated Shunt Server:tuic-client $($(first_type tuic-client) --version) Started!"
 		# FIXME: ipt2socks cannot handle udp reply from tuic
 		# FIXME: ipt2socks cannot handle udp reply from tuic
-		redir_udp=0
+		#redir_udp=0
+		;;
+	shadowtls)
+		[ -n "$tmp_local_port" ] && tmp_port=$tmp_local_port || tmp_port=$tmp_shunt_local_port
+		gen_config_file $SHUNT_SERVER $type 3 "10${tmp_shunt_port}" $tmp_port chain/$tmp_shunt_port #make a redir:303 and a socks:304
+		#echo "debug \$tmp_port=$tmp_port, \$tmp_shunt_port=${tmp_shunt_port},  \$tmp_shunt_local_port=$tmp_shunt_local_port"
+		ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_config_file
+		ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:"${tmp_port}" 8.8.8.8:53 127.0.0.1:$tmp_shunt_dns_port -q
+		local chain_type=$(uci_get_by_name $SHUNT_SERVER chain_type)
+		case ${chain_type} in
+			vmess)
+				ln_start_bin $(first_type xray v2ray) v2ray run -c $shunt_config_file
+				echolog "Netflix Separated Shunt Server:shadow-tls chain-to$($(first_type xray) --version) Started!"
+				;;
+			 sslocal)
+				ln_start_bin $(first_type sslocal) sslocal -c $shunt_config_file
+				echolog "Netflix Separated Shunt Server:shadow-tls chain-to$($(first_type sslocal) --version) Started!"
+				;;
+		esac
 		;;
 		;;
 	# socks5)
 	# socks5)
 	# 	if [ "$(uci_get_by_name $SHUNT_SERVER auth_enable 0)" == "1" ]; then
 	# 	if [ "$(uci_get_by_name $SHUNT_SERVER auth_enable 0)" == "1" ]; then
@@ -517,7 +584,7 @@ start_local() {
 	[ "$LOCAL_SERVER" == "$SHUNT_SERVER" ] && tmp_local_port=$local_port
 	[ "$LOCAL_SERVER" == "$SHUNT_SERVER" ] && tmp_local_port=$local_port
 	local type=$(uci_get_by_name $LOCAL_SERVER type)
 	local type=$(uci_get_by_name $LOCAL_SERVER type)
 	case "$type" in
 	case "$type" in
-	ss | ssr)
+	ss | ssr | ss_rust)
 		gen_config_file $LOCAL_SERVER $type 4 $local_port
 		gen_config_file $LOCAL_SERVER $type 4 $local_port
 		ss_program="$(first_type ${type}local ${type}-local)"
 		ss_program="$(first_type ${type}local ${type}-local)"
 		ln_start_bin $ss_program ${type}-local -c $local_config_file
 		ln_start_bin $ss_program ${type}-local -c $local_config_file
@@ -538,21 +605,40 @@ start_local() {
 	naiveproxy)
 	naiveproxy)
 		gen_config_file $LOCAL_SERVER $type 4 $local_port
 		gen_config_file $LOCAL_SERVER $type 4 $local_port
 		ln_start_bin $(first_type naive) naive --config $local_config_file
 		ln_start_bin $(first_type naive) naive --config $local_config_file
-		echolog "Global_Socks5:$($(first_type $type) --version | head -1) Started!"
+		echolog "Global_Socks5:$($(first_type naive) --version | head -1) Started!"
 		;;
 		;;
 	hysteria)
 	hysteria)
 		if [ "$_local" == "2" ]; then
 		if [ "$_local" == "2" ]; then
 			gen_config_file $LOCAL_SERVER $type 4 0 $local_port
 			gen_config_file $LOCAL_SERVER $type 4 0 $local_port
 			ln_start_bin $(first_type hysteria) hysteria client --config $local_config_file
 			ln_start_bin $(first_type hysteria) hysteria client --config $local_config_file
-			echolog "Global_Socks5:$($(first_type hysteria) --version | awk '{print $1,$3}') Started!"
+			echolog "Global_Socks5:$($(first_type hysteria) version | awk '{print $1,$3}') Started!"
 		fi
 		fi
 		;;
 		;;
 	tuic)
 	tuic)
 		if [ "$_local" == "2" ]; then
 		if [ "$_local" == "2" ]; then
 			gen_config_file $LOCAL_SERVER $type 4 $local_port
 			gen_config_file $LOCAL_SERVER $type 4 $local_port
 			ln_start_bin $(first_type tuic-client) tuic-client --config $local_config_file
 			ln_start_bin $(first_type tuic-client) tuic-client --config $local_config_file
+			echolog "Global Socks5:tuic-client $($(first_type tuic-client) --version) Started!"
+		fi
+		;;
+	shadowtls)
+		#respective config for global socks and main node
+		if [ "$_local" == "2" ]; then
+			gen_config_file $LOCAL_SERVER $type 4 "10${tmp_tcp_local_port}"
+			gen_config_file $LOCAL_SERVER $type 4 0 $local_port chain/"10${tmp_tcp_local_port}"
+			ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_local_config_file
+			local chain_type=$(uci_get_by_name $LOCAL_SERVER chain_type)
+			case ${chain_type} in
+				vmess)
+					ln_start_bin $(first_type xray v2ray) v2ray run -c $local_config_file
+					echolog "Global Socks5 Proxy:shadow-tls chain-to$($(first_type xray) --version) Started!"
+					;;
+				sslocal)
+					ln_start_bin $(first_type sslocal) sslocal -c $local_config_file
+					echolog "Global Socks5 Proxy:shadow-tls chain-to$($(first_type sslocal) --version) Started!"
+					;;
+			esac
 		fi
 		fi
-		echolog "Global_Socks5:tuic-client $($(first_type tuic-client) --version) Started!"
 		;;
 		;;
 	*)
 	*)
 		[ -e /proc/sys/net/ipv6 ] && local listenip='-i ::'
 		[ -e /proc/sys/net/ipv6 ] && local listenip='-i ::'
@@ -620,14 +706,43 @@ Start_Run() {
 	hysteria)
 	hysteria)
 		gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port
 		gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port
 		ln_start_bin $(first_type hysteria) hysteria client --config $tcp_config_file
 		ln_start_bin $(first_type hysteria) hysteria client --config $tcp_config_file
-		echolog "Main node:$($(first_type hysteria) --version | awk '{print $1,$3}') Started!"
+		echolog "Main node:$($(first_type hysteria) version | awk '{print $1,$3}') Started!"
 		;;
 		;;
 	tuic)
 	tuic)
+		local PARAM
+		[ $mode == "tcp" ] && PARAM="-T" || PARAM=""
 		gen_config_file $GLOBAL_SERVER $type 1 $tmp_tcp_local_port
 		gen_config_file $GLOBAL_SERVER $type 1 $tmp_tcp_local_port
 		ln_start_bin $(first_type tuic-client) tuic-client --config $tcp_config_file
 		ln_start_bin $(first_type tuic-client) tuic-client --config $tcp_config_file
-		ln_start_bin $(first_type ipt2socks) ipt2socks -R -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_tcp_local_port -l $tcp_port
+		ln_start_bin $(first_type ipt2socks) ipt2socks "$PARAM" -R -b 0.0.0.0 -4 -s 127.0.0.1 -p $tmp_tcp_local_port -l $tcp_port
+		if [ -n $socks_port ] && [ $GLOBAL_SERVER == $LOCAL_SERVER ]; then #start a new tuic instance
+			gen_config_file $GLOBAL_SERVER $type 4 $socks_port
+			ln_start_bin $(first_type tuic-client) tuic-client --config $local_config_file
+			echolog "Global Socks5:tuic-client $($(first_type tuic-client) --version) Started!"
+		fi
 		echolog "Main node:tuic-client $($(first_type tuic-client) --version) Started!"
 		echolog "Main node:tuic-client $($(first_type tuic-client) --version) Started!"
 		;;
 		;;
+	shadowtls)
+		if [ -z "$socks_port" ]; then
+			gen_config_file $GLOBAL_SERVER $type 1 "10${tmp_tcp_local_port}"
+			gen_config_file $GLOBAL_SERVER $type 1 "10${tmp_tcp_local_port}" 0 chain
+		else
+			gen_config_file $GLOBAL_SERVER $type 1 "10${tmp_tcp_local_port}"
+			gen_config_file $GLOBAL_SERVER $type 1 "10${tmp_tcp_local_port}" $socks_port chain
+		fi
+		local chain_type=$(uci_get_by_name $GLOBAL_SERVER chain_type)
+		case ${chain_type} in
+		vmess)
+			ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_config_file
+			ln_start_bin $(first_type xray v2ray) v2ray run -c $tcp_config_file
+			echolog "Mian node:shadow-tls chain-to $($(first_type xray) --version) Started!"
+			;;
+		sslocal)
+			ln_start_bin $(first_type shadow-tls) shadow-tls config --config $chain_config_file
+			ln_start_bin $(first_type sslocal) sslocal -c $tcp_config_file
+			echolog "Main node:shadow-tls chain-to $($(first_type sslocal) --version) Started!"
+			;;
+		esac
+		;;
 	socks5)
 	socks5)
 		if [ "$(uci_get_by_name $GLOBAL_SERVER auth_enable 0)" == "1" ]; then
 		if [ "$(uci_get_by_name $GLOBAL_SERVER auth_enable 0)" == "1" ]; then
 			local auth="-a $(uci_get_by_name $GLOBAL_SERVER username) -k $(uci_get_by_name $GLOBAL_SERVER password)"
 			local auth="-a $(uci_get_by_name $GLOBAL_SERVER username) -k $(uci_get_by_name $GLOBAL_SERVER password)"
@@ -981,6 +1096,7 @@ reset() {
 		set shadowsocksr.@global[0].switch_time='667'
 		set shadowsocksr.@global[0].switch_time='667'
 		set shadowsocksr.@global[0].switch_timeout='5'
 		set shadowsocksr.@global[0].switch_timeout='5'
 		set shadowsocksr.@global[0].switch_try_count='3'
 		set shadowsocksr.@global[0].switch_try_count='3'
+#		set shadowsocksr.@global[0].default_packet_encoding='xudp'
 		set shadowsocksr.@global[0].gfwlist_url='https://fastly.jsdelivr.net/gh/YW5vbnltb3Vz/domain-list-community@release/gfwlist.txt'
 		set shadowsocksr.@global[0].gfwlist_url='https://fastly.jsdelivr.net/gh/YW5vbnltb3Vz/domain-list-community@release/gfwlist.txt'
 		set shadowsocksr.@global[0].chnroute_url='https://ispip.clang.cn/all_cn.txt'
 		set shadowsocksr.@global[0].chnroute_url='https://ispip.clang.cn/all_cn.txt'
 		set shadowsocksr.@global[0].nfip_url='https://fastly.jsdelivr.net/gh/QiuSimons/Netflix_IP/NF_only.txt'
 		set shadowsocksr.@global[0].nfip_url='https://fastly.jsdelivr.net/gh/QiuSimons/Netflix_IP/NF_only.txt'

+ 168 - 55
luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua

@@ -8,6 +8,9 @@ local proto = arg[2]
 local local_port = arg[3] or "0"
 local local_port = arg[3] or "0"
 local socks_port = arg[4] or "0"
 local socks_port = arg[4] or "0"
 
 
+local chain = arg[5] or "0"
+local chain_local_port = string.split(chain, "/")[2] or "0"
+
 local server = ucursor:get_all("shadowsocksr", server_section)
 local server = ucursor:get_all("shadowsocksr", server_section)
 local outbound_settings = nil
 local outbound_settings = nil
 
 
@@ -275,71 +278,151 @@ local ss = {
 	reuse_port = true
 	reuse_port = true
 }
 }
 local hysteria = {
 local hysteria = {
-	server = server.server .. ":" .. server.server_port,
-	protocol = server.hysteria_protocol,
-	up_mbps = tonumber(server.uplink_capacity),
-	down_mbps = tonumber(server.downlink_capacity),
+	server = server.server_port and (server.server .. ":" .. server.server_port) or (server.server .. ":" .. server.port_range),
+	bandwidth = {
+	up = tonumber(server.uplink_capacity) and tonumber(server.uplink_capacity) .. " mbps" or nil,
+	down = tonumber(server.downlink_capacity) and tonumber(server.downlink_capacity) .. " mbps" or nil 
+	},
 	socks5 = (proto:find("tcp") and tonumber(socks_port) and tonumber(socks_port) ~= 0) and {
 	socks5 = (proto:find("tcp") and tonumber(socks_port) and tonumber(socks_port) ~= 0) and {
-		listen = "0.0.0.0:" .. tonumber(socks_port),
-		timeout = 300,
-		disable_udp = false
+			listen = "0.0.0.0:" .. tonumber(socks_port),
+			disable_udp = false
+	} or nil,
+--[[			tcpTProxy = (proto:find("tcp") and local_port ~= "0") and {
+	listen = "0.0.0.0:" .. tonumber(local_port)
+} or nil,]]
+	tcpRedirect = (proto:find("tcp") and local_port ~= "0") and {
+					listen = "0.0.0.0:" .. tonumber(local_port)
 	} or nil,
 	} or nil,
-	redirect_tcp = (proto:find("tcp") and local_port ~= "0") and {
-		listen = "0.0.0.0:" .. tonumber(local_port),
-		timeout = 300
+	udpTProxy = (proto:find("udp") and local_port ~= "0") and {
+					listen = "0.0.0.0:" .. tonumber(local_port)
 	} or nil,
 	} or nil,
-	tproxy_udp = (proto:find("udp") and local_port ~= "0") and {
-		listen = "0.0.0.0:" .. tonumber(local_port),
-		timeout = 60
+	obfs = (server.flag_obfs == "1") and {
+				type = server.obfs_type,
+				salamander = { password = server.salamander }
 	} or nil,
 	} or nil,
-	obfs = server.seed,
-	auth = (server.auth_type == "1") and server.auth_payload or nil,
-	auth_str = (server.auth_type == "2") and server.auth_payload or nil,
-	alpn = server.quic_tls_alpn,
-	server_name = server.tls_host,
-	insecure = (server.insecure == "1") and true or false,
-	ca = (server.certificate) and server.certpath or nil,
-	recv_window_conn = tonumber(server.recv_window_conn),
-	recv_window = tonumber(server.recv_window),
-	disable_mtu_discovery = (server.disable_mtu_discovery == "1") and true or false,
+	quic = (server.flag_quicparam == "1" ) and {
+		initStreamReceiveWindow = (server.initstreamreceivewindow and server.initstreamreceivewindow or nil),
+		maxStreamReceiveWindow = (server.maxstreamseceivewindow and server.maxstreamseceivewindow or nil),
+		initConnReceiveWindow = (server.initconnreceivewindow and server.initconnreceivewindow or nil),
+		maxConnReceiveWindow = (server.maxconnreceivewindow and server.maxconnreceivewindow or nil),
+		maxIdleTimeout = (server.maxincomingstreams and server.maxincomingstreams or nil),
+		keepAlivePeriod = (server.maxincomingstreams and server.keepaliveperiod or nil),
+		disable_mtu_discovery = (server.disablepathmtudiscovery == "1") and true or false
+	} or nil,
+	auth = server.hy2_auth,
+	tls = (server.tls_host) and {
+		sni = server.tls_host,
+		insecure = (server.insecure == "1") and true or false,
+		pinSHA256 = (server.insecure == "1") and server.pinsha256 or nil
+	} or {
+		sni = server.server,
+		insecure = (server.insecure == "1") and true or false
+	},
 	fast_open = (server.fast_open == "1") and true or false,
 	fast_open = (server.fast_open == "1") and true or false,
-	lazy_start = (server.lazy_start == "1") and true or false
+	lazy = (server.lazy_mode == "1") and true or false
 }
 }
 local shadowtls = {
 local shadowtls = {
-        client = {
-                server_addr = server.server .. ":" .. server.server_port,
-                listen = "127.0.0.1:" .. tonumber(local_port),
-                tls_names = server.shadowtls_sni,
-                password = server.password 
-        },
-        v3 = (server.shadowtls_protocol == "v3") and true or false,
-        disable_nodelay = (server.disable_nodelay == "1") and true or false,
-        fastopen = (server.fastopen == "1") and true or false,
-        strict = (server.strict == "1") and true or false
+	client = {
+		server_addr = server.server_port and server.server .. ":" .. server.server_port or nil,
+		listen = "127.0.0.1:" .. tonumber(local_port),
+		tls_names = server.shadowtls_sni,
+		password = server.password 
+	},
+	v3 = (server.shadowtls_protocol == "v3") and true or false,
+	disable_nodelay = (server.disable_nodelay == "1") and true or false,
+	fastopen = (server.fastopen == "1") and true or false,
+	strict = (server.strict == "1") and true or false
+}
+local chain_sslocal = {
+		locals = local_port ~= "0" and {
+		{
+			local_address = "0.0.0.0",
+			local_port = (chain_local_port == "0" and tonumber(server.local_port) or tonumber(chain_local_port)),
+			mode = (proto:find("tcp,udp") and "tcp_and_udp") or proto .. "_only",
+			protocol = "redir",
+			tcp_redir = "redirect",
+		--tcp_redir = "tproxy",
+			udp_redir = "tproxy"
+		},
+		socks_port ~= "0" and {
+			protocol = "socks",
+			local_address = "0.0.0.0",
+			local_port = tonumber(socks_port)
+		} or nil
+	} or {{ 
+			protocol = "socks",
+			local_address = "0.0.0.0",
+			ocal_port = tonumber(socks_port)
+			}},
+		servers = {
+			{
+				server = "127.0.0.1",
+				server_port = (tonumber(local_port) == 0 and tonumber(chain_local_port) or tonumber(local_port)),
+				method = server.sslocal_method,
+				password = server.sslocal_password
+			}
+		}
+}
+local chain_vmess = {
+	inbounds = (local_port ~= "0") and {
+	{
+		port =  (chain_local_port == "0" and tonumber(server.local_port) or tonumber(chain_local_port)),
+		protocol = "dokodemo-door",
+			settings = {
+			network = proto, 
+			followRedirect = true
+		},
+		streamSettings = {
+			sockopt = {tproxy = "redirect"}
+		},
+		sniffing = {
+			enable = true,
+			destOverride = {"http","tls"}
+		}
+	},
+		(proto:find("tcp") and socks_port ~= "0") and {
+		protocol = "socks",
+		port = tonumber(socks_port)
+		} or nil
+	} or { protocol = "socks",port = tonumber(socks_port) },
+	outbound = {
+		protocol = "vmess",
+		settings = {
+			vnext = {{
+				address = "127.0.0.1",
+				port =  (tonumber(local_port) == 0 and tonumber(chain_local_port) or tonumber(local_port)),
+				users = {{
+				id = (server.vmess_uuid),
+				security = server.vmess_method,
+				level = 0
+				}}
+			}}
+		}
+	}
 }
 }
 local tuic = {
 local tuic = {
 		relay = {
 		relay = {
-				server = server.server .. ":" .. server.server_port,
-				ip = server.tuic_ip,
-				uuid = server.tuic_uuid,
-				password = server.tuic_passwd,
-				certificates = server.certificate and { server.certpath } or nil,
-				udp_relay_mode = server.udp_relay_mode,
-				congestion_control = server.congestion_control,
-				heartbeat = server.heartbeat and server.heartbeat .. "s" or nil,
-				timeout = server.timeout and server.timeout .. "s" or nil,
-				gc_interval = server.gc_interval and server.gc_interval .. "s" or nil,
-				gc_lifetime = server.gc_lifetime and server.gc_lifetime .. "s" or nil,
-				alpn = server.tls_alpn,
-				disable_sni = (server.disable_sni == "1") and true or false,
-				zero_rtt_handshake = (server.zero_rtt_handshake == "1") and true or false,
-				send_window = tonumber(server.send_window),
-				receive_window = tonumber(server.receive_window)
-        },
+			server = server.server_port and server.server .. ":" .. server.server_port,
+			ip = server.tuic_ip,
+			uuid = server.tuic_uuid,
+			password = server.tuic_passwd,
+			certificates = server.certificate and { server.certpath } or nil,
+			udp_relay_mode = server.udp_relay_mode,
+			congestion_control = server.congestion_control,
+			heartbeat = server.heartbeat and server.heartbeat .. "s" or nil,
+			timeout = server.timeout and server.timeout .. "s" or nil,
+			gc_interval = server.gc_interval and server.gc_interval .. "s" or nil,
+			gc_lifetime = server.gc_lifetime and server.gc_lifetime .. "s" or nil,
+			alpn = server.tls_alpn,
+			disable_sni = (server.disable_sni == "1") and true or false,
+			zero_rtt_handshake = (server.zero_rtt_handshake == "1") and true or false,
+			send_window = tonumber(server.send_window),
+			receive_window = tonumber(server.receive_window)
+		},
 		["local"] = {
 		["local"] = {
-				server = "[::]:" .. tonumber(local_port),
-				dual_stack = (server.tuic_dual_stack == "1") and true or false,
-				max_packet_size = tonumber(server.tuic_max_package_size)
+			server = tonumber(socks_port) and  "[::]:" .. (socks_port == "0" and local_port or tonumber(socks_port)),
+			dual_stack = (server.tuic_dual_stack == "1") and true or false,
+			max_packet_size = tonumber(server.tuic_max_package_size)
 		}
 		}
 }
 }
 local config = {}
 local config = {}
@@ -351,6 +434,14 @@ function config:new(o)
 end
 end
 function config:handleIndex(index)
 function config:handleIndex(index)
 	local switch = {
 	local switch = {
+		ss_rust = function()
+			ss.protocol = socks_port
+			if server.plugin and server.plugin ~= "none" then
+				ss.plugin = server.plugin
+				ss.plugin_opts = server.plugin_opts or nil
+			end
+			print(json.stringify(ss, 1))
+		end,
 		ss = function()
 		ss = function()
 			ss.protocol = socks_port
 			ss.protocol = socks_port
 			if server.plugin and server.plugin ~= "none" then
 			if server.plugin and server.plugin ~= "none" then
@@ -379,6 +470,28 @@ function config:handleIndex(index)
 		hysteria = function()
 		hysteria = function()
 			print(json.stringify(hysteria, 1))
 			print(json.stringify(hysteria, 1))
 		end,
 		end,
+		shadowtls = function()
+			local chain_switch = {
+				sslocal = function()
+					if (chain:find("chain")) then
+						print(json.stringify(chain_sslocal, 1))
+					else
+						print(json.stringify(shadowtls, 1))
+					end
+				end,
+				vmess = function()
+					if (chain:find("chain")) then
+						print(json.stringify(chain_vmess, 1))
+					else
+						print(json.stringify(shadowtls, 1))
+					end
+				end
+			}
+			local ChainType = server.chain_type
+				if chain_switch[ChainType] then
+					chain_switch[ChainType]()
+				end
+			end,
 		tuic = function()
 		tuic = function()
 			print(json.stringify(tuic, 1))
 			print(json.stringify(tuic, 1))
 		end
 		end
@@ -388,4 +501,4 @@ function config:handleIndex(index)
 	end
 	end
 end
 end
 local f = config:new()
 local f = config:new()
-f:handleIndex(server.type)
+f:handleIndex(server.type)

+ 65 - 0
shadow-tls/Makefile

@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/package.mk
+
+PKG_NAME:=shadow-tls
+PKG_VERSION:=0.2.23
+PKG_RELEASE:=1
+
+PKG_LICENSE_FILES:=LICENSE
+PKG_MAINTAINER:=FluffyTigerFear
+RELEASE_HEAD:=$(PKG_NAME)
+RELEASE_FOOT:=unknown-linux-musl
+ifeq ($(ARCH),aarch64)
+	RELEASE_ARCH:=$(RELEASE_HEAD)-aarch64-$(RELEASE_FOOT)
+	PKG_HASH:=c29eaaf3bc05115acc7453ac26bacf9aff65211b1e8ca7f771b818248bec8601
+else ifeq ($(ARCH),arm)
+	ARM_CPU_FEATURES:=$(word 2,$(subst +,$(space),$(call qstrip,$(CONFIG_CPU_TYPE))))
+	ifeq ($(ARM_CPU_FEATURES),)
+		RELEASE_ARCH:=$(RELEASE_HEAD)-armv7-$(RELEASE_FOOT)eabi
+		PKG_HASH:=eb1346ec83e154f2722ab671fbcdd1c95739b4a7c29655effae9cd4ffe8d23b6
+	else
+		RELEASE_ARCH:=$(RELEASE_HEAD)-armv7-$(RELEASE_FOOT)eabihf
+		PKG_HASH:=be005c23a4d5c51d52f2a96f1f060734dd43b80a7912516c130d433d04c7dfa1
+	endif
+else ifeq ($(ARCH),x86_64)
+	RELEASE_ARCH:=$(RELEASE_HEAD)-x86_64-$(RELEASE_FOOT)
+	PKG_HASH:=acc7296e50cf310a15fca5756efa5f721ffc62dd0e4dd16581bc229b21b4b549
+else
+	PKG_SOURCE:=dummy
+	PKG_HASH:=dummy
+endif
+
+define Download/shadow-tls
+	URL:=https://github.com/ihciah/shadow-tls/releases/download/v$(PKG_VERSION)
+	URL_FILE:=$(RELEASE_ARCH)
+	FILE:=$(RELEASE_ARCH)
+	HASH:=$(PKG_HASH)
+endef
+
+define Package/shadow-tls
+	SECTION:=net
+	CATEGORY:=Network
+	SUBMENU:=Web Servers/Proxies
+	TITLE:=A proxy to expose real tls handshake to the firewall.
+	URL:=https://github.com/ihciah/shadow-tls
+	DEPENDS:=@USE_MUSL @(aarch64||arm||x86_64) @!(TARGET_x86_geode||TARGET_x86_legacy)
+endef
+
+define Build/Prepare
+	$(call Build/Prepare/Default)
+ifneq ($(CONFIG_PACKAGE_shadow-tls),)
+	$(call Download,shadow-tls)
+endif
+endef
+
+define Build/Compile
+endef
+
+define Package/shadow-tls/install
+	$(INSTALL_DIR) $(1)/usr/bin
+	$(INSTALL_BIN) $(DL_DIR)/$(RELEASE_ARCH) $(1)/usr/bin/shadow-tls
+endef
+
+$(eval $(call BuildPackage,shadow-tls))