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
This commit is contained in:
TeF 2023-09-28 12:14:14 +08:00 committed by sbwml
parent 18bf808bef
commit 16faf622f6
5 changed files with 603 additions and 168 deletions

View File

@ -11,6 +11,7 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
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_Kcptun \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
@ -28,7 +29,7 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server \
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_DEPENDS:= \
@(PACKAGE_libustream-mbedtls||PACKAGE_libustream-openssl||PACKAGE_libustream-wolfssl) \
@ -42,6 +43,7 @@ LUCI_DEPENDS:= \
+PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG:chinadns-ng \
+PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
+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_Kcptun:kcptun-client \
+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
@ -128,6 +130,14 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Tuic_Client
depends on !(TARGET_x86_geode||TARGET_x86_legacy)
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
bool "Include IPT2Socks"
default n

View File

@ -144,8 +144,11 @@ end
if is_finded("ssr-redir") then
o:value("ssr", translate("ShadowsocksR"))
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
if is_finded("trojan") then
o:value("trojan", translate("Trojan"))
@ -159,6 +162,9 @@ end
if is_finded("tuic-client") then
o:value("tuic", translate("TUIC"))
end
if is_finded("shadow-tls") and is_finded("sslocal") then
o:value("shadowtls", translate("Shadow-TLS"))
end
if is_finded("ipt2socks") then
o:value("socks5", translate("Socks5"))
end
@ -196,23 +202,27 @@ o.datatype = "host"
o.rmempty = false
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "ss_rust")
o:depends("type", "v2ray")
o:depends("type", "trojan")
o:depends("type", "naiveproxy")
o:depends("type", "hysteria")
o:depends("type", "tuic")
o:depends("type", "shadowtls")
o:depends("type", "socks5")
o = s:option(Value, "server_port", translate("Server Port"))
o.datatype = "port"
o.rmempty = ({port_hopping=0 and false or true})
o.rmempty = true
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "ss_rust")
o:depends("type", "v2ray")
o:depends("type", "trojan")
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", "shadowtls")
o:depends("type", "socks5")
o = s:option(Flag, "auth_enable", translate("Enable Authentication"))
@ -234,8 +244,10 @@ o.password = true
o.rmempty = true
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "ss_rust")
o:depends("type", "trojan")
o:depends("type", "naiveproxy")
o:depends("type", "shadowtls")
o:depends({type = "socks5", 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})
@ -255,6 +267,7 @@ for _, v in ipairs(encrypt_methods_ss) do
end
o.rmempty = true
o:depends("type", "ss")
o:depends("type", "ss_rust")
o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
o = s:option(Flag, "uot", translate("UDP over TCP"))
@ -282,10 +295,12 @@ if is_finded("xray-plugin") then
end
o.rmempty = true
o:depends("type", "ss")
o:depends("type", "ss_rust")
o = s:option(Value, "plugin_opts", translate("Plugin Opts"))
o.rmempty = true
o:depends("type", "ss")
o:depends("type", "ss_rust")
o = s:option(ListValue, "protocol", translate("Protocol"))
for _, v in ipairs(protocol) do
@ -307,56 +322,163 @@ o:depends("type", "ssr")
o = s:option(Value, "obfs_param", translate("Obfs param (optional)"))
o:depends("type", "ssr")
-- [[ Hysteria ]]--
o = s:option(Flag, "port_hopping", translate("Enable Port Hopping"))
o:depends("type", "hysteria")
o.rmempty = true
o.default = "0"
o = s:option(Value, "port_range", translate("Port Range"))
o:depends({type = "hysteria", port_hopping = "1"})
o.datatype = "portrange"
o.rmempty = true
-- [[ 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:value("wechat-video", translate("wechat-video"))
o:value("faketcp", translate("faketcp"))
o.default = "udp"
o.rmempty = true
o = s:option(ListValue, "auth_type", translate("Authentication type"))
o:depends("type", "hysteria")
o:value("0", translate("disabled"))
o:value("1", translate("base64"))
o:value("2", translate("string"))
o.rmempty = true
o = s:option(Value, "auth_payload", translate("Authentication payload"))
o:depends({type = "hysteria", auth_type = "1"})
o:depends({type = "hysteria", auth_type = "2"})
o.rmempty = true
o = s:option(Value, "recv_window", translate("QUIC connection receive window"))
o.datatype = "uinteger"
o:depends("type", "hysteria")
o.rmempty = true
o = s:option(Value, "recv_window_conn", translate("QUIC stream receive window"))
o.datatype = "uinteger"
o:depends("type", "hysteria")
o.rmempty = true
o = s:option(Flag, "disable_mtu_discovery", translate("Disable Path MTU discovery"))
o:depends("type", "hysteria")
o.rmempty = true
o = s:option(Flag, "lazy_start", translate("Lazy Start"))
o = s:option(Flag, "port_hopping", translate("Port Hopping"))
o:depends("type", "hysteria")
o.rmempty = true
o.default = "0"
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.default = "0"
o = s:option(Flag, "flag_obfs", translate("Enable Obfuscation"))
o:depends("type", "hysteria")
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(Flag, "flag_quicparam", translate("Hysterir QUIC parameters"))
o:depends("type", "hysteria")
o.rmempty = true
o.default = "0"
--[[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.default = "8388608"
o = s:option(Value, "maxstreamseceivewindow", translate("QUIC maxStreamReceiveWindow"))
o:depends({type = "hysteria",flag_quicparam = "1"})
o.datatype = "uinteger"
o.rmempty = true
o.default = "8388608"
o = s:option(Value, "initconnreceivewindow", translate("QUIC initConnReceiveWindow"))
o:depends({type = "hysteria",flag_quicparam = "1"})
o.datatype = "uinteger"
o.rmempty = true
o.default = "20971520"
o = s:option(Value, "maxconnreceivewindow", translate("QUIC maxConnReceiveWindow"))
o:depends({type = "hysteria",flag_quicparam = "1"})
o.datatype = "uinteger"
o.rmempty = true
o.default = "20971520"
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.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.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 ]]
-- TuicNameId
o = s:option(Value, "tuic_uuid", translate("TUIC User UUID"))
@ -420,29 +542,29 @@ o.rmempty = true
o = s:option(Value, "send_window", translate("TUIC send window"))
o:depends("type", "tuic")
o.datatype = "uinteger"
o.default = 16777216
o.default = 20971520
o.rmempty = true
o = s:option(Value, "receive_window", translate("TUIC receive window"))
o:depends("type", "tuic")
o.datatype = "uinteger"
o.default = 8388608
o.default = 10485760
o.rmempty = true
o = s:option(Flag, "disable_sni", translate("Disable SNI"))
o:depends("type", "tuic")
o.default = 0
o.default = "0"
o.rmempty = true
o = s:option(Flag, "zero_rtt_handshake", translate("Enable 0-RTT QUIC handshake"))
o:depends("type", "tuic")
o.default = 0
o.default = "0"
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.default = 0
o.default = "0"
o.rmempty = true
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:depends("transport", "kcp")
o:depends("type", "hysteria")
o.rmempty = true
o = s:option(Flag, "congestion", translate("Congestion"))
@ -791,6 +912,11 @@ o:depends("tls", true)
o:depends("type", "hysteria")
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 ]]--
o = s:option(Flag, "mux", translate("Mux"))
o.rmempty = false
@ -864,6 +990,7 @@ o.rmempty = true
o.default = "0"
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "ss_rust")
o:depends("type", "trojan")
o:depends("type", "hysteria")
@ -882,22 +1009,26 @@ if is_finded("kcptun-client") then
o.default = "0"
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "ss_rust")
o = s:option(Value, "kcp_port", translate("KcpTun Port"))
o.datatype = "port"
o.default = 4000
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "ss_rust")
o = s:option(Value, "kcp_password", translate("KcpTun Password"))
o.password = true
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "ss_rust")
o = s:option(Value, "kcp_param", translate("KcpTun Param"))
o.default = "--nocomp"
o:depends("type", "ssr")
o:depends("type", "ss")
o:depends("type", "ss_rust")
end
return m

View File

@ -106,14 +106,78 @@ msgstr "混淆参数(可选)"
msgid "Authentication type"
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"
msgstr "启用端口跃迁"
msgid "Port Range"
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"
msgstr "QUIC 连接接收窗口"
@ -121,6 +185,7 @@ msgstr "QUIC 连接接收窗口"
msgid "QUIC stream receive window"
msgstr "QUIC 流接收窗口"
msgid "Lazy Start"
msgstr "延迟启动"

View File

@ -18,13 +18,17 @@ LOG_FILE=/var/log/ssrplus.log
TMP_PATH=/var/etc/ssrplus
TMP_BIN_PATH=$TMP_PATH/bin
TMP_DNSMASQ_PATH=/tmp/dnsmasq.d/dnsmasq-ssrplus.d
chain_config_file= #generate shadowtls chain proxy config file
tcp_config_file=
udp_config_file=
shunt_config_file=
local_config_file=
shunt_dns_config_file=
tmp_local_port=
ARG_UDP=
dns_port="5335" #dns port
china_dns_port="5333" #china_dns_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_dns_port="305" #shunt dns2socks temporary port
tmp_tcp_local_port="306" #tcp socks temporary port
server_count=0
redir_tcp=0
redir_udp=0
@ -217,60 +222,67 @@ start_dns() {
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
local fastopen="true"
fastopen="true"
else
local fastopen="false"
fastopen="false"
fi
if [ $1 == "ssr" ]; then
case $1 in
ssr)
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() {
case "$1" in
ss) echo "Shadowsocks" ;;
ssr) echo "ShadowsocksR" ;;
ss_rust) echo "Shadowsocks-Rust";;
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
1)
config_file=$tcp_config_file
chain_config_file=$(echo ${config_file}|sed 's/ssrplus\//ssrplus\/chain-/')
;;
2)
config_file=$udp_config_file
chain_config_file=$(echo ${config_file}|sed 's/ssrplus\//ssrplus\/chain-/')
;;
3)
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
fi
config_file=$shunt_config_file
chain_config_file=$(echo ${config_file}|sed 's/ssrplus\//ssrplus\/chain-/')
;;
4)
local ss_protocol="socks"
config_file=$local_config_file
chain_config_file=$(echo ${config_file}|sed 's/ssrplus\//ssrplus\/chain-/')
;;
esac
case "$2" in
ss | ssr)
ss | ssr | ss_rust)
lua /usr/share/shadowsocksr/gen_config.lua $1 $mode $4 ${ss_protocol:-redir} >$config_file
if [ "$3" == "3" ]; then
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
;;
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)
/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
;;
esac
sed -i 's/\\//g' $TMP_PATH/*-ssr-*.json
sed -i 's/\\//g' $TMP_PATH/*-ssr-*.json #>/dev/null > 2>&1
}
start_udp() {
@ -376,17 +408,34 @@ start_udp() {
hysteria)
gen_config_file $UDP_RELAY_SERVER $type 2 $tmp_udp_port
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)
# 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
# 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!"
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)
# if [ "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0)" == "1" ]; then
@ -408,7 +457,7 @@ start_udp() {
start_shunt() {
local type=$(uci_get_by_name $SHUNT_SERVER type)
case "$type" in
ss | ssr)
ss | ssr |ss_rust)
gen_config_file $SHUNT_SERVER $type 3 $tmp_shunt_port
ss_program="$(first_type ${type}local ${type}-redir)"
ln_start_bin $ss_program ${type}-redir -c $shunt_config_file
@ -463,21 +512,39 @@ start_shunt() {
fi
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
echolog "shunt:$($(first_type hysteria) --version | awk '{print $1,$3}') Started!"
echolog "shunt:$($(first_type hysteria) version | awk '{print $1,$3}') Started!"
;;
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
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
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)
# 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 type=$(uci_get_by_name $LOCAL_SERVER type)
case "$type" in
ss | ssr)
ss | ssr | ss_rust)
gen_config_file $LOCAL_SERVER $type 4 $local_port
ss_program="$(first_type ${type}local ${type}-local)"
ln_start_bin $ss_program ${type}-local -c $local_config_file
@ -538,21 +605,40 @@ start_local() {
naiveproxy)
gen_config_file $LOCAL_SERVER $type 4 $local_port
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)
if [ "$_local" == "2" ]; then
gen_config_file $LOCAL_SERVER $type 4 0 $local_port
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
;;
tuic)
if [ "$_local" == "2" ]; then
gen_config_file $LOCAL_SERVER $type 4 $local_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
;;
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
echolog "Global_Socks5:tuic-client $($(first_type tuic-client) --version) Started!"
;;
*)
[ -e /proc/sys/net/ipv6 ] && local listenip='-i ::'
@ -620,14 +706,43 @@ Start_Run() {
hysteria)
gen_config_file $GLOBAL_SERVER $type 1 $tcp_port $socks_port
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)
local PARAM
[ $mode == "tcp" ] && PARAM="-T" || PARAM=""
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 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!"
;;
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)
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)"
@ -964,6 +1079,7 @@ reset() {
set shadowsocksr.@global[0].switch_time='667'
set shadowsocksr.@global[0].switch_timeout='5'
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].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'

View File

@ -8,6 +8,9 @@ local proto = arg[2]
local local_port = arg[3] 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 outbound_settings = nil
@ -275,71 +278,151 @@ local ss = {
reuse_port = true
}
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 {
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,
redirect_tcp = (proto:find("tcp") and local_port ~= "0") and {
listen = "0.0.0.0:" .. tonumber(local_port),
timeout = 300
--[[ 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,
tproxy_udp = (proto:find("udp") and local_port ~= "0") and {
listen = "0.0.0.0:" .. tonumber(local_port),
timeout = 60
udpTProxy = (proto:find("udp") and local_port ~= "0") and {
listen = "0.0.0.0:" .. tonumber(local_port)
} 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,
obfs = (server.flag_obfs == "1") and {
type = server.obfs_type,
salamander = { password = server.salamander }
} or nil,
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,
lazy_start = (server.lazy_start == "1") and true or false
lazy = (server.lazy_mode == "1") and true or false
}
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 = {
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"] = {
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 = {}
@ -351,6 +434,14 @@ function config:new(o)
end
function config:handleIndex(index)
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.protocol = socks_port
if server.plugin and server.plugin ~= "none" then
@ -379,6 +470,28 @@ function config:handleIndex(index)
hysteria = function()
print(json.stringify(hysteria, 1))
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()
print(json.stringify(tuic, 1))
end