luci: update Hysteria to Hysteria2 logic

No longer compatible with Hysteria V1. If you want to use, please use Sing-Box for implementation.
This commit is contained in:
xiaorouji 2023-09-14 01:19:26 +08:00 committed by sbwml
parent 45421e6cb3
commit e8c7527ff4
10 changed files with 176 additions and 223 deletions

View File

@ -6,22 +6,20 @@ if not api.finded_com("hysteria") then
return
end
local type_name = "Hysteria"
local type_name = "Hysteria2"
local option_prefix = "hysteria_"
local option_prefix = "hysteria2_"
local function option_name(name)
return option_prefix .. name
end
-- [[ Hysteria ]]
-- [[ Hysteria2 ]]
s.fields["type"]:value(type_name, translate("Hysteria"))
s.fields["type"]:value(type_name, "Hysteria2")
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
o:value("udp", "UDP")
o:value("faketcp", "faketcp")
o:value("wechat-video", "wechat-video")
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
@ -34,19 +32,8 @@ o.rewrite_option = o.option
o = s:option(Value, option_name("obfs"), translate("Obfs Password"))
o.rewrite_option = o.option
o = s:option(ListValue, option_name("auth_type"), translate("Auth Type"))
o:value("disable", translate("Disable"))
o:value("string", translate("STRING"))
o:value("base64", translate("BASE64"))
o.rewrite_option = o.option
o = s:option(Value, option_name("auth_password"), translate("Auth Password"))
o.password = true
o:depends({ [option_name("auth_type")] = "string"})
o:depends({ [option_name("auth_type")] = "base64"})
o.rewrite_option = o.option
o = s:option(Value, option_name("alpn"), translate("QUIC TLS ALPN"))
o.rewrite_option = o.option
o = s:option(Flag, option_name("fast_open"), translate("Fast Open"))
@ -58,11 +45,14 @@ o = s:option(Flag, option_name("tls_allowInsecure"), translate("allowInsecure"),
o.default = "0"
o = s:option(Value, option_name("up_mbps"), translate("Max upload Mbps"))
o.default = "10"
o.default = "100"
o.rewrite_option = o.option
o = s:option(Value, option_name("down_mbps"), translate("Max download Mbps"))
o.default = "50"
o.default = "100"
o.rewrite_option = o.option
o = s:option(Value, option_name("hop_interval"), translate("Hop Interval"))
o.rewrite_option = o.option
o = s:option(Value, option_name("recv_window_conn"), translate("QUIC stream receive window"))
@ -71,19 +61,11 @@ o.rewrite_option = o.option
o = s:option(Value, option_name("recv_window"), translate("QUIC connection receive window"))
o.rewrite_option = o.option
o = s:option(Value, option_name("handshake_timeout"), translate("Handshake Timeout"))
o.rewrite_option = o.option
o = s:option(Value, option_name("idle_timeout"), translate("Idle Timeout"))
o.rewrite_option = o.option
o = s:option(Value, option_name("hop_interval"), translate("Hop Interval"))
o.rewrite_option = o.option
o = s:option(Flag, option_name("disable_mtu_discovery"), translate("Disable MTU detection"))
o.rewrite_option = o.option
o = s:option(Flag, option_name("lazy_start"), translate("Lazy Start"))
o.default = "0"
o.rewrite_option = o.option
api.luci_types(arg[1], m, s, type_name, option_prefix)

View File

@ -6,40 +6,26 @@ if not api.finded_com("hysteria") then
return
end
local type_name = "Hysteria"
local type_name = "Hysteria2"
local option_prefix = "hysteria_"
local option_prefix = "hysteria2_"
local function option_name(name)
return option_prefix .. name
end
-- [[ Hysteria ]]
-- [[ Hysteria2 ]]
s.fields["type"]:value(type_name, translate("Hysteria"))
s.fields["type"]:value(type_name, "Hysteria2")
o = s:option(Value, option_name("port"), translate("Listen Port"))
o.datatype = "port"
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
o:value("udp", "UDP")
o:value("faketcp", "faketcp")
o:value("wechat-video", "wechat-video")
o = s:option(Value, option_name("obfs"), translate("Obfs Password"))
o.rewrite_option = o.option
o = s:option(ListValue, option_name("auth_type"), translate("Auth Type"))
o:value("disable", translate("Disable"))
o:value("string", translate("STRING"))
o.rewrite_option = o.option
o = s:option(Value, option_name("auth_password"), translate("Auth Password"))
o.password = true
o:depends({ [option_name("auth_type")] = "string" })
o.rewrite_option = o.option
o = s:option(Value, option_name("alpn"), translate("QUIC TLS ALPN"))
o.rewrite_option = o.option
o = s:option(Flag, option_name("udp"), translate("UDP"))
@ -47,40 +33,19 @@ o.default = "1"
o.rewrite_option = o.option
o = s:option(Value, option_name("up_mbps"), translate("Max upload Mbps"))
o.default = "10"
o.default = "100"
o.rewrite_option = o.option
o = s:option(Value, option_name("down_mbps"), translate("Max download Mbps"))
o.default = "50"
o.default = "100"
o.rewrite_option = o.option
o = s:option(Value, option_name("recv_window_conn"), translate("QUIC stream receive window"))
o = s:option(Flag, option_name("ignoreClientBandwidth"), translate("ignoreClientBandwidth"))
o.default = "0"
o.rewrite_option = o.option
o = s:option(Value, option_name("recv_window"), translate("QUIC connection receive window"))
o.rewrite_option = o.option
o = s:option(Flag, option_name("disable_mtu_discovery"), translate("Disable MTU detection"))
o.rewrite_option = o.option
o = s:option(Flag, option_name("tls"), translate("TLS"))
o.default = 0
o.validate = function(self, value, t)
if value then
if value == "1" then
local ca = s.fields[option_name("tls_certificateFile")]:formvalue(t) or ""
local key = s.fields[option_name("tls_keyFile")]:formvalue(t) or ""
if ca == "" or key == "" then
return nil, translate("Public key and Private key path can not be empty!")
end
end
return value
end
end
o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
o:depends({ [option_name("tls")] = true })
o.validate = function(self, value, t)
if value and value ~= "" then
if not nixio.fs.access(value) then
@ -94,7 +59,6 @@ end
o = s:option(FileUpload, option_name("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
o:depends({ [option_name("tls")] = true })
o.validate = function(self, value, t)
if value and value ~= "" then
if not nixio.fs.access(value) then

View File

@ -735,6 +735,9 @@ function to_check(arch, app_name)
end
local remote_version = json.tag_name
if com[app_name].remote_version_str_replace then
remote_version = remote_version:gsub(com[app_name].remote_version_str_replace, "")
end
local has_update = compare_versions(local_version:match("[^v]+"), "<", remote_version:match("[^v]+"))
if not has_update then

View File

@ -24,6 +24,7 @@ _M.hysteria = {
repo = "HyNetwork/hysteria",
get_url = gh_release_url,
cmd_version = "version | awk '/^Version:/ {print $2}'",
remote_version_str_replace = "app/",
zipped = false,
default_path = "/usr/bin/hysteria",
match_fmt_str = "linux%%-%s$",

View File

@ -164,8 +164,8 @@ local function start()
brook_path_arg = " --path " .. brook_path
end
bin = ln_run(api.get_app_path("brook"), "brook_" .. id, string.format("--debug %s -l :%s -p %s%s", brook_protocol, port, brook_password, brook_path_arg), log_path)
elseif type == "Hysteria" then
config = require(require_dir .. "util_hysteria").gen_config_server(user)
elseif type == "Hysteria2" then
config = require(require_dir .. "util_hysteria2").gen_config_server(user)
bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path)
end

View File

@ -1,119 +0,0 @@
module("luci.passwall.util_hysteria", package.seeall)
local api = require "luci.passwall.api"
local uci = api.uci
local jsonc = api.jsonc
function gen_config_server(node)
local config = {
listen = ":" .. node.port,
protocol = node.protocol or "udp",
obfs = node.hysteria_obfs,
cert = node.tls_certificateFile,
key = node.tls_keyFile,
auth = (node.hysteria_auth_type == "string") and {
mode = "password",
config = {
password = node.hysteria_auth_password
}
} or nil,
disable_udp = (node.hysteria_udp == "0") and true or false,
alpn = node.hysteria_alpn or nil,
up_mbps = tonumber(node.hysteria_up_mbps) or 10,
down_mbps = tonumber(node.hysteria_down_mbps) or 50,
recv_window_conn = (node.hysteria_recv_window_conn) and tonumber(node.hysteria_recv_window_conn) or nil,
recv_window = (node.hysteria_recv_window) and tonumber(node.hysteria_recv_window) or nil,
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery) and true or false
}
return config
end
function gen_config(var)
local node_id = var["-node"]
if not node_id then
print("-node 不能为空")
return
end
local node = uci:get_all("passwall", node_id)
local local_tcp_redir_port = var["-local_tcp_redir_port"]
local local_udp_redir_port = var["-local_udp_redir_port"]
local local_socks_address = var["-local_socks_address"] or "0.0.0.0"
local local_socks_port = var["-local_socks_port"]
local local_socks_username = var["-local_socks_username"]
local local_socks_password = var["-local_socks_password"]
local local_http_address = var["-local_http_address"] or "0.0.0.0"
local local_http_port = var["-local_http_port"]
local local_http_username = var["-local_http_username"]
local local_http_password = var["-local_http_password"]
local tcp_proxy_way = var["-tcp_proxy_way"]
local server_host = var["-server_host"] or node.address
local server_port = var["-server_port"] or node.port
if api.is_ipv6(server_host) then
server_host = api.get_ipv6_full(server_host)
end
local server = server_host .. ":" .. server_port
if (node.hysteria_hop) then
server = server .. "," .. node.hysteria_hop
end
local config = {
server = server,
protocol = node.protocol or "udp",
obfs = node.hysteria_obfs,
auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil,
auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil,
alpn = node.hysteria_alpn or nil,
server_name = node.tls_serverName,
insecure = (node.tls_allowInsecure == "1") and true or false,
up_mbps = tonumber(node.hysteria_up_mbps) or 10,
down_mbps = tonumber(node.hysteria_down_mbps) or 50,
retry = -1,
retry_interval = 5,
recv_window_conn = (node.hysteria_recv_window_conn) and tonumber(node.hysteria_recv_window_conn) or nil,
recv_window = (node.hysteria_recv_window) and tonumber(node.hysteria_recv_window) or nil,
handshake_timeout = (node.hysteria_handshake_timeout) and tonumber(node.hysteria_handshake_timeout) or nil,
idle_timeout = (node.hysteria_idle_timeout) and tonumber(node.hysteria_idle_timeout) or nil,
hop_interval = (node.hysteria_hop_interval) and tonumber(node.hysteria_hop_interval) or nil,
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery) and true or false,
fast_open = (node.fast_open == "1") and true or false,
lazy_start = (node.hysteria_lazy_start) and true or false,
socks5 = (local_socks_address and local_socks_port) and {
listen = local_socks_address .. ":" .. local_socks_port,
timeout = 300,
disable_udp = false,
user = (local_socks_username and local_socks_password) and local_socks_username,
password = (local_socks_username and local_socks_password) and local_socks_password,
} or nil,
http = (local_http_address and local_http_port) and {
listen = local_http_address .. ":" .. local_http_port,
timeout = 300,
disable_udp = false,
user = (local_http_username and local_http_password) and local_http_username,
password = (local_http_username and local_http_password) and local_http_password,
} or nil,
redirect_tcp = ("redirect" == tcp_proxy_way and local_tcp_redir_port) and {
listen = "0.0.0.0:" .. local_tcp_redir_port,
timeout = 300
} or nil,
tproxy_tcp = ("tproxy" == tcp_proxy_way and local_tcp_redir_port) and {
listen = "0.0.0.0:" .. local_tcp_redir_port,
timeout = 300
} or nil,
tproxy_udp = (local_udp_redir_port) and {
listen = "0.0.0.0:" .. local_udp_redir_port,
timeout = 60
} or nil
}
return jsonc.stringify(config, 1)
end
_G.gen_config = gen_config
if arg[1] then
local func =_G[arg[1]]
if func then
print(func(api.get_function_args(arg)))
end
end

View File

@ -0,0 +1,127 @@
module("luci.passwall.util_hysteria2", package.seeall)
local api = require "luci.passwall.api"
local uci = api.uci
local jsonc = api.jsonc
function gen_config_server(node)
local config = {
listen = ":" .. node.port,
tls = {
cert = node.tls_certificateFile,
key = node.tls_keyFile,
},
obfs = {
type = "salamander",
salamander = {
password = node.hysteria2_obfs
}
},
auth = {
type = "password",
password = node.hysteria2_auth_password
},
bandwidth = {
up = node.hysteria2_up_mbps and node.hysteria2_up_mbps .. " mbps" or "1 gbps",
down = node.hysteria2_down_mbps and node.hysteria2_down_mbps .. " mbps" or "1 gbps",
},
ignoreClientBandwidth = (node.hysteria2_ignoreClientBandwidth == "1") and true or false,
disable_udp = (node.hysteria2_udp == "0") and true or false,
}
return config
end
function gen_config(var)
local node_id = var["-node"]
if not node_id then
print("-node 不能为空")
return
end
local node = uci:get_all("passwall", node_id)
local local_tcp_redir_port = var["-local_tcp_redir_port"]
local local_udp_redir_port = var["-local_udp_redir_port"]
local local_socks_address = var["-local_socks_address"] or "0.0.0.0"
local local_socks_port = var["-local_socks_port"]
local local_socks_username = var["-local_socks_username"]
local local_socks_password = var["-local_socks_password"]
local local_http_address = var["-local_http_address"] or "0.0.0.0"
local local_http_port = var["-local_http_port"]
local local_http_username = var["-local_http_username"]
local local_http_password = var["-local_http_password"]
local tcp_proxy_way = var["-tcp_proxy_way"]
local server_host = var["-server_host"] or node.address
local server_port = var["-server_port"] or node.port
if api.is_ipv6(server_host) then
server_host = api.get_ipv6_full(server_host)
end
local server = server_host .. ":" .. server_port
if (node.hysteria2_hop) then
server = server .. "," .. node.hysteria2_hop
end
local config = {
server = server,
transport = {
type = node.protocol or "udp",
udp = {
hopInterval = node.hysteria2_hop_interval and node.hysteria2_hop_interval .. "s" or "30s"
}
},
obfs = {
type = "salamander",
salamander = {
password = node.hysteria2_obfs
}
},
auth = node.hysteria2_auth_password,
tls = {
sni = node.tls_serverName,
insecure = (node.tls_allowInsecure == "1") and true or false
},
quic = {
initStreamReceiveWindow = (node.hysteria2_recv_window) and tonumber(node.hysteria2_recv_window) or nil,
initConnReceiveWindow = (node.hysteria2_recv_window_conn) and tonumber(node.hysteria2_recv_window_conn) or nil,
maxIdleTimeout = (node.hysteria2_idle_timeout) and tonumber(node.hysteria2_idle_timeout) or nil,
disablePathMTUDiscovery = (node.hysteria2_disable_mtu_discovery) and true or false,
},
bandwidth = {
up = node.hysteria2_up_mbps and node.hysteria2_up_mbps .. " mbps" or "100 mbps",
down = node.hysteria2_down_mbps and node.hysteria2_down_mbps .. " mbps" or "100 mbps"
},
fast_open = (node.fast_open == "1") and true or false,
lazy = true,
socks5 = (local_socks_address and local_socks_port) and {
listen = local_socks_address .. ":" .. local_socks_port,
username = (local_socks_username and local_socks_password) and local_socks_username or nil,
password = (local_socks_username and local_socks_password) and local_socks_password or nil,
disable_udp = false,
} or nil,
http = (local_http_address and local_http_port) and {
listen = local_http_address .. ":" .. local_http_port,
username = (local_http_username and local_http_password) and local_http_username or nil,
password = (local_http_username and local_http_password) and local_http_password or nil,
disable_udp = false,
} or nil,
tcpRedirect = ("redirect" == tcp_proxy_way and local_tcp_redir_port) and {
listen = "0.0.0.0:" .. local_tcp_redir_port
} or nil,
tcpTProxy = ("tproxy" == tcp_proxy_way and local_tcp_redir_port) and {
listen = "0.0.0.0:" .. local_tcp_redir_port
} or nil,
udpTProxy = (local_udp_redir_port) and {
listen = "0.0.0.0:" .. local_udp_redir_port
} or nil
}
return jsonc.stringify(config, 1)
end
_G.gen_config = gen_config
if arg[1] then
local func =_G[arg[1]]
if func then
print(func(api.get_function_args(arg)))
end
end

View File

@ -145,9 +145,9 @@ local api = require "luci.passwall.api"
} else if (v_type === "Brook") {
dom_prefix = "brook_"
protocol = "brook"
} else if (v_type === "Hysteria") {
dom_prefix = "hysteria_"
protocol = "hysteria"
} else if (v_type === "Hysteria2") {
dom_prefix = "hysteria2_"
protocol = "hysteria2"
} else if (v_type === "Xray") {
dom_prefix = "xray_"
} else if (v_type === "sing-box") {
@ -453,17 +453,14 @@ local api = require "luci.passwall.api"
}
url += url_protocol;
url += params;
} else if (v_type === "Hysteria") {
} else if (v_type === "Hysteria2") {
var v_port = opt.get(dom_prefix + "port");
var params = "";
params += opt.query("protocol", dom_prefix + "protocol");
params += opt.query("auth", dom_prefix + "auth_password");
params += opt.query("peer", dom_prefix + "tls_serverName");
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("insecure", dom_prefix + "tls_allowInsecure");
params += opt.query("upmbps", dom_prefix + "up_mbps", 1000);
params += opt.query("downmbps", dom_prefix + "down_mbps", 1000);
params += opt.query("alpn", dom_prefix + "alpn");
params += opt.query("obfsParam", dom_prefix + "obfs");
params += opt.query("obfs", "salamander");
params += opt.query("obfs-password", dom_prefix + "obfs");
var url =
_address + ":" +
v_port.value + "?" +
@ -1040,13 +1037,13 @@ local api = require "luci.passwall.api"
opt.set('remarks', decodeURI(m.hash.substr(1)));
}
}
if (ssu[0] === "hysteria") {
if (ssu[0] === "hysteria2") {
if (has_singbox) {
opt.set('type', "sing-box");
dom_prefix = "singbox_"
} else {
opt.set('type', "Hysteria");
dom_prefix = "hysteria_"
opt.set('type', "Hysteria2");
dom_prefix = "hysteria2_"
}
var m = parseNodeUrl(ssrurl);
var queryParam = {};
@ -1062,17 +1059,12 @@ local api = require "luci.passwall.api"
}
opt.set(dom_prefix + 'address', m.hostname);
opt.set(dom_prefix + 'port', m.port || "443");
opt.set(dom_prefix + 'protocol', queryParam.protocol);
opt.set(dom_prefix + 'obfs', queryParam.obfsParam);
opt.set(dom_prefix + 'auth_type', "string");
opt.set(dom_prefix + 'auth_password', queryParam.auth);
opt.set(dom_prefix + 'tls_serverName', queryParam.peer);
opt.set(dom_prefix + 'obfs', queryParam["obfs-password"]);
opt.set(dom_prefix + 'auth', queryParam.auth);
opt.set(dom_prefix + 'tls_serverName', queryParam.sni);
if (queryParam.insecure && queryParam.insecure == "1") {
opt.set(dom_prefix + 'tls_allowInsecure', true);
}
opt.set(dom_prefix + 'alpn', queryParam.alpn);
opt.set(dom_prefix + 'up_mbps', queryParam.upmbps);
opt.set(dom_prefix + 'down_mbps', queryParam.downmbps);
if (m.hash) {
opt.set('remarks', decodeURI(m.hash.substr(1)));
}

View File

@ -517,6 +517,9 @@ msgstr "QUIC 并发双向流的最大数量"
msgid "Disable MTU detection"
msgstr "禁用 MTU 检测"
msgid "ignoreClientBandwidth"
msgstr "忽略客户端带宽设置"
msgid "Lazy Start"
msgstr "延迟启动"

View File

@ -37,7 +37,7 @@ UTIL_SS=$LUA_UTIL_PATH/util_shadowsocks.lua
UTIL_XRAY=$LUA_UTIL_PATH/util_xray.lua
UTIL_TROJAN=$LUA_UTIL_PATH/util_trojan.lua
UTIL_NAIVE=$LUA_UTIL_PATH/util_naiveproxy.lua
UTIL_HYSTERIA=$LUA_UTIL_PATH/util_hysteria.lua
UTIL_HYSTERIA2=$LUA_UTIL_PATH/util_hysteria2.lua
UTIL_TUIC=$LUA_UTIL_PATH/util_tuic.lua
echolog() {
@ -656,13 +656,13 @@ run_socks() {
lua $UTIL_SS gen_config -node $node -local_socks_port $socks_port -server_host $server_host -server_port $port ${_extra_param} > $config_file
ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v
;;
hysteria)
hysteria2)
[ "$http_port" != "0" ] && {
http_flag=1
config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g")
local _extra_param="-local_http_port $http_port"
}
lua $UTIL_HYSTERIA gen_config -node $node -local_socks_port $socks_port -server_host $server_host -server_port $port ${_extra_param} > $config_file
lua $UTIL_HYSTERIA2 gen_config -node $node -local_socks_port $socks_port -server_host $server_host -server_port $port ${_extra_param} > $config_file
ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client
;;
tuic)
@ -768,8 +768,8 @@ run_redir() {
lua $UTIL_SS gen_config -node $node -local_udp_redir_port $local_port > $config_file
ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v
;;
hysteria)
lua $UTIL_HYSTERIA gen_config -node $node -local_udp_redir_port $local_port > $config_file
hysteria2)
lua $UTIL_HYSTERIA2 gen_config -node $node -local_udp_redir_port $local_port > $config_file
ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client
;;
tuic)
@ -983,7 +983,7 @@ run_redir() {
lua $UTIL_SS gen_config -node $node ${_extra_param} > $config_file
ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v
;;
hysteria)
hysteria2)
local _extra_param="-local_tcp_redir_port $local_port"
[ "$tcp_node_socks" = "1" ] && {
tcp_node_socks_flag=1
@ -1002,7 +1002,7 @@ run_redir() {
_extra_param="${_extra_param} -local_udp_redir_port $local_port"
}
_extra_param="${_extra_param} -tcp_proxy_way $tcp_proxy_way"
lua $UTIL_HYSTERIA gen_config -node $node ${_extra_param} > $config_file
lua $UTIL_HYSTERIA2 gen_config -node $node ${_extra_param} > $config_file
ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client
;;
esac
@ -1771,8 +1771,8 @@ WHEN_CHNROUTE_DEFAULT_DNS=$(config_t_get global when_chnroute_default_dns direct
FILTER_PROXY_IPV6=$(config_t_get global filter_proxy_ipv6 0)
dns_listen_port=${DNS_PORT}
REDIRECT_LIST="socks ss ss-rust ssr sing-box xray trojan-go trojan-plus naiveproxy hysteria"
TPROXY_LIST="brook socks ss ss-rust ssr sing-box xray trojan-go trojan-plus hysteria"
REDIRECT_LIST="socks ss ss-rust ssr sing-box xray trojan-go trojan-plus naiveproxy hysteria2"
TPROXY_LIST="brook socks ss ss-rust ssr sing-box xray trojan-go trojan-plus hysteria2"
RESOLVFILE=/tmp/resolv.conf.d/resolv.conf.auto
[ -f "${RESOLVFILE}" ] && [ -s "${RESOLVFILE}" ] || RESOLVFILE=/tmp/resolv.conf.auto