update 2026-05-21 10:49:42

This commit is contained in:
action committed 2026-05-21 10:49:42 +08:00
1 parent 6792f24236
commit c94416953e
6 files changed
+507 -72

No files matched your search

@@ -222,6 +222,14 @@ if #hysteria2_type > 0 then
for key, value in pairs(hysteria2_type) do
o:value(value)
end
o = s:option(Value, "hysteria_up_mbps", "Hy/Hy2 " .. translate("Max upload Mbps"))
o.datatype = "uinteger"
o.default = "100"
o = s:option(Value, "hysteria_down_mbps", "Hy/Hy2 " .. translate("Max download Mbps"))
o.datatype = "uinteger"
o.default = "100"
end
o = s:option(Flag, "boot_update", translate("Update Once on Boot"), translate("Updates the subscription the first time PassWall runs automatically after each system boot."))
@@ -505,6 +505,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
local sub_vmess_type = DEFAULT_VMESS_TYPE
local sub_vless_type = DEFAULT_VLESS_TYPE
local sub_hysteria2_type = DEFAULT_HYSTERIA2_TYPE
local sub_hy_up_mbps, sub_hy_down_mbps = 1000, 1000
if sub_cfg then
if sub_cfg.allowInsecure and sub_cfg.allowInsecure ~= "1" then
sub_allowinsecure = nil
@@ -529,6 +530,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
if hysteria2_type ~= "global" and core_has[hysteria2_type] then
sub_hysteria2_type = hysteria2_type
end
sub_hy_up_mbps = sub_cfg.hysteria_up_mbps
sub_hy_down_mbps = sub_cfg.hysteria_down_mbps
end
local result = {
timeout = 60,
@@ -1351,8 +1354,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
result.alpn = params.alpn
result.hysteria_up_mbps = params.upmbps
result.hysteria_down_mbps = params.downmbps
result.hysteria_up_mbps = params.upmbps or sub_hy_up_mbps
result.hysteria_down_mbps = params.downmbps or sub_hy_down_mbps
result.hysteria_hop = params.mport
elseif szType == 'hysteria2' or szType == 'hy2' then
@@ -1396,8 +1399,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.tls_CertByName = params.vcn
local insecure = params.allowinsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
result.hysteria2_up_mbps = params.upmbps
result.hysteria2_down_mbps = params.downmbps
result.hysteria2_up_mbps = params.upmbps or sub_hy_up_mbps
result.hysteria2_down_mbps = params.downmbps or sub_hy_down_mbps
result.hysteria2_hop = params.mport
if params["obfs-password"] or params["obfs_password"] then
result.hysteria2_obfs_type = "salamander"
@@ -7,68 +7,39 @@ require "nixio.fs"
local m, s, o
local sid = arg[1]
-- 加密方式(SS/SSR用)
local encrypt_methods = {
"rc4-md5",
"rc4-md5-6",
"rc4",
"table",
"aes-128-cfb",
"aes-192-cfb",
"aes-256-cfb",
"aes-128-ctr",
"aes-192-ctr",
"aes-256-ctr",
"bf-cfb",
"camellia-128-cfb",
"camellia-192-cfb",
"camellia-256-cfb",
"cast5-cfb",
"des-cfb",
"idea-cfb",
"rc2-cfb",
"seed-cfb",
"salsa20",
"chacha20",
"chacha20-ietf"
"rc4-md5", "rc4-md5-6", "rc4", "table",
"aes-128-cfb", "aes-192-cfb", "aes-256-cfb",
"aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
"cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb",
"salsa20", "chacha20", "chacha20-ietf"
}
local encrypt_methods_ss = {
-- aead
"aes-128-gcm",
"aes-192-gcm",
"aes-256-gcm",
"chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305",
-- aead 2022
"2022-blake3-aes-128-gcm",
"2022-blake3-aes-256-gcm",
"2022-blake3-chacha20-poly1305"
--[[ stream
"table",
"rc4",
"rc4-md5",
"aes-128-cfb",
"aes-192-cfb",
"aes-256-cfb",
"aes-128-ctr",
"aes-192-ctr",
"aes-256-ctr",
"bf-cfb",
"camellia-128-cfb",
"camellia-192-cfb",
"camellia-256-cfb",
"salsa20",
"chacha20",
"chacha20-ietf" ]]
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm",
"chacha20-ietf-poly1305", "xchacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
}
-- Shadowsocks 加密方法(Xray 版)
local v_ss_encrypt_method_list = {
"aes-128-cfb", "aes-256-cfb", "aes-128-gcm", "aes-256-gcm",
"chacha20", "chacha20-ietf", "chacha20-poly1305", "chacha20-ietf-poly1305"
}
-- 伪装类型(用于 mKCP/QUIC)
local header_type_list = {
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
}
local protocol = {"origin"}
obfs = {"plain", "http_simple", "http_post"}
m = Map("shadowsocksr", translate("Edit ShadowSocksR Server"))
m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/server")
if m.uci:get("shadowsocksr", sid) ~= "server_config" then
luci.http.redirect(m.redirect)
return
@@ -79,6 +50,7 @@ s = m:section(NamedSection, sid, "server_config")
s.anonymous = true
s.addremove = false
-- ========== 基本设置 ==========
o = s:option(Flag, "enable", translate("Enable"))
o.default = 1
o.rmempty = false
@@ -91,6 +63,13 @@ end
if nixio.fs.access("/usr/bin/ssr-server") then
o:value("ssr", translate("ShadowsocksR"))
end
-- Xray 协议支持
if nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/libexec/xray") then
o:value("vmess", "VMess (Xray)")
o:value("vless", "VLESS (Xray)")
o:value("trojan", "Trojan (Xray)")
o:value("shadowsocks", "Shadowsocks (Xray)")
end
o.default = "socks5"
o = s:option(Value, "server_port", translate("Server Port"))
@@ -114,32 +93,30 @@ o:depends("type", "socks5")
o = s:option(Value, "password", translate("Password"))
o.password = true
o.rmempty = false
o:depends("type", "socks5")
o:depends("type", "ss")
o:depends("type", "ssr")
o:depends("type", "trojan")
o:depends("type", "shadowsocks")
-- ========== SS/SSR 协议特有 ==========
o = s:option(ListValue, "encrypt_method", translate("Encrypt Method"))
for _, v in ipairs(encrypt_methods) do
o:value(v)
end
for _, v in ipairs(encrypt_methods) do o:value(v) end
o.rmempty = false
o:depends("type", "ssr")
o = s:option(ListValue, "encrypt_method_ss", translate("Encrypt Method"))
for _, v in ipairs(encrypt_methods_ss) do
o:value(v)
end
for _, v in ipairs(encrypt_methods_ss) do o:value(v) end
o.rmempty = false
o:depends("type", "ss")
o = s:option(ListValue, "protocol", translate("Protocol"))
for _, v in ipairs(protocol) do
o:value(v)
end
for _, v in ipairs(protocol) do o:value(v) end
o.rmempty = false
o:depends("type", "ssr")
o = s:option(ListValue, "obfs", translate("Obfs"))
for _, v in ipairs(obfs) do
o:value(v)
end
for _, v in ipairs(obfs) do o:value(v) end
o.rmempty = false
o:depends("type", "ssr")
@@ -151,4 +128,269 @@ o.rmempty = false
o:depends("type", "ss")
o:depends("type", "ssr")
return m
-- ========== Xray 协议通用字段 ==========
-- 用户备注
o = s:option(Value, "remarks", translate("Remarks"))
o.default = translate("Remarks")
o.rmempty = true
o:depends("type", "vmess")
o:depends("type", "vless")
o:depends("type", "trojan")
o:depends("type", "shadowsocks")
-- 用户等级
o = s:option(Value, "level", translate("User Level"))
o.datatype = "uinteger"
o.default = 1
o.rmempty = true
o:depends("type", "vmess")
o:depends("type", "vless")
o:depends("type", "shadowsocks")
o:depends("type", "trojan")
-- ========== Xray 协议认证字段 ==========
-- UUID (用于 vmess/vless)
o = s:option(Value, "uuid", translate("UUID"))
o.description = translate("Required for VMess/VLESS. Generate with: uuidgen")
o.rmempty = true
o:depends("type", "vmess")
o:depends("type", "vless")
-- Trojan 密码
o = s:option(Value, "trojan_password", translate("Trojan Password"))
o.password = true
o.rmempty = true
o:depends("type", "trojan")
-- Shadowsocks 密码和加密(Xray 内置)
o = s:option(Value, "ss_password", translate("Shadowsocks Password"))
o.password = true
o.rmempty = true
o:depends("type", "shadowsocks")
o = s:option(ListValue, "ss_method", translate("Encrypt Method"))
for _, v in ipairs(v_ss_encrypt_method_list) do o:value(v) end
o.default = "chacha20-ietf-poly1305"
o.rmempty = true
o:depends("type", "shadowsocks")
o = s:option(ListValue, "ss_network", translate("Transport"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("tcp,udp", "TCP,UDP")
o.default = "tcp,udp"
o.rmempty = true
o:depends("type", "shadowsocks")
-- VMess alterId
o = s:option(Value, "alter_id", translate("Alter ID"))
o.datatype = "uinteger"
o.default = 0
o.rmempty = true
o:depends("type", "vmess")
-- VLESS decryption
o = s:option(Value, "decryption", translate("Decryption"))
o.default = "none"
o.rmempty = true
o:depends("type", "vless")
-- ========== TLS / XTLS 设置 ==========
o = s:option(Flag, "tls", translate("TLS"))
o.default = 0
o.rmempty = true
o:depends("type", "vmess")
o:depends("type", "vless")
o:depends("type", "trojan")
o:depends("type", "shadowsocks")
o = s:option(Flag, "xtls", translate("XTLS"))
o.default = 0
o.rmempty = true
o:depends({ type = "vless", tls = "1" })
o = s:option(ListValue, "flow", translate("Flow"))
o:value("xtls-rprx-origin", "xtls-rprx-origin")
o:value("xtls-rprx-origin-udp443", "xtls-rprx-origin-udp443")
o:value("xtls-rprx-direct", "xtls-rprx-direct")
o:value("xtls-rprx-direct-udp443", "xtls-rprx-direct-udp443")
o:value("xtls-rprx-splice", "xtls-rprx-splice")
o:value("xtls-rprx-splice-udp443", "xtls-rprx-splice-udp443")
o.default = "xtls-rprx-direct"
o.rmempty = true
o:depends("xtls", "1")
o = s:option(Value, "tls_serverName", translate("Server Name (SNI)"))
o.rmempty = true
o:depends("tls", "1")
o = s:option(Value, "tls_certificateFile", translate("Certificate File Path"))
o.description = translate("e.g.: /etc/ssl/fullchain.pem")
o.rmempty = true
o:depends("tls", "1")
o = s:option(Value, "tls_keyFile", translate("Private Key File Path"))
o.description = translate("e.g.: /etc/ssl/private.key")
o.rmempty = true
o:depends("tls", "1")
-- ========== 传输层设置 (Transport) ==========
o = s:option(ListValue, "transport", translate("Transport Protocol"))
o:value("tcp", "TCP")
o:value("mkcp", "mKCP")
o:value("ws", "WebSocket")
o:value("h2", "HTTP/2")
o:value("ds", "DomainSocket")
o:value("quic", "QUIC")
o.default = "tcp"
o.rmempty = true
o:depends("type", "vmess")
o:depends("type", "vless")
o:depends("type", "trojan")
-- ----- WebSocket 设置 -----
o = s:option(Value, "ws_host", translate("WebSocket Host"))
o.rmempty = true
o:depends("transport", "ws")
o:depends("type", "vmess")
o:depends("type", "vless")
o:depends("type", "trojan")
o = s:option(Value, "ws_path", translate("WebSocket Path"))
o.default = "/"
o.rmempty = true
o:depends("transport", "ws")
o:depends("type", "vmess")
o:depends("type", "vless")
o:depends("type", "trojan")
-- ----- HTTP/2 设置 -----
o = s:option(Value, "h2_host", translate("HTTP/2 Host"))
o.rmempty = true
o:depends("transport", "h2")
o:depends("type", "vmess")
o:depends("type", "vless")
o = s:option(Value, "h2_path", translate("HTTP/2 Path"))
o.default = "/"
o.rmempty = true
o:depends("transport", "h2")
o:depends("type", "vmess")
o:depends("type", "vless")
-- ----- TCP 伪装设置 -----
o = s:option(ListValue, "tcp_guise", translate("TCP Camouflage Type"))
o:value("none", "none")
o:value("http", "http")
o.default = "none"
o.rmempty = true
o:depends("transport", "tcp")
o:depends("type", "vmess")
o:depends("type", "vless")
o = s:option(DynamicList, "tcp_guise_http_host", translate("HTTP Host"))
o.rmempty = true
o:depends("tcp_guise", "http")
o = s:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path"))
o.rmempty = true
o:depends("tcp_guise", "http")
-- ----- mKCP 设置 -----
o = s:option(ListValue, "mkcp_guise", translate("mKCP Camouflage Type"))
for _, v in ipairs(header_type_list) do o:value(v) end
o.default = "none"
o.rmempty = true
o:depends("transport", "mkcp")
o = s:option(Value, "mkcp_mtu", translate("KCP MTU"))
o.datatype = "uinteger"
o.default = 1350
o.rmempty = true
o:depends("transport", "mkcp")
o = s:option(Value, "mkcp_tti", translate("KCP TTI"))
o.datatype = "uinteger"
o.default = 20
o.rmempty = true
o:depends("transport", "mkcp")
o = s:option(Value, "mkcp_uplinkCapacity", translate("KCP Uplink Capacity"))
o.datatype = "uinteger"
o.default = 5
o.rmempty = true
o:depends("transport", "mkcp")
o = s:option(Value, "mkcp_downlinkCapacity", translate("KCP Downlink Capacity"))
o.datatype = "uinteger"
o.default = 20
o.rmempty = true
o:depends("transport", "mkcp")
o = s:option(Flag, "mkcp_congestion", translate("KCP Congestion Control"))
o.default = 0
o.rmempty = true
o:depends("transport", "mkcp")
o = s:option(Value, "mkcp_readBufferSize", translate("KCP Read Buffer Size"))
o.datatype = "uinteger"
o.default = 1
o.rmempty = true
o:depends("transport", "mkcp")
o = s:option(Value, "mkcp_writeBufferSize", translate("KCP Write Buffer Size"))
o.datatype = "uinteger"
o.default = 1
o.rmempty = true
o:depends("transport", "mkcp")
o = s:option(Value, "mkcp_seed", translate("KCP Seed"))
o.datatype = "uinteger"
o.rmempty = true
o:depends("transport", "mkcp")
-- ----- DomainSocket 设置 -----
o = s:option(Value, "ds_path", translate("DomainSocket Path"))
o.description = translate("A legal file path. This file must not exist before running.")
o.rmempty = true
o:depends("transport", "ds")
-- ----- QUIC 设置 -----
o = s:option(ListValue, "quic_security", translate("QUIC Security"))
o:value("none", "none")
o:value("aes-128-gcm", "aes-128-gcm")
o:value("chacha20-poly1305", "chacha20-poly1305")
o.default = "none"
o.rmempty = true
o:depends("transport", "quic")
o = s:option(Value, "quic_key", translate("QUIC Key"))
o.rmempty = true
o:depends("transport", "quic")
o = s:option(ListValue, "quic_guise", translate("QUIC Camouflage Type"))
for _, v in ipairs(header_type_list) do o:value(v) end
o.default = "none"
o.rmempty = true
o:depends("transport", "quic")
-- ========== 访问控制 ==========
o = s:option(Flag, "bind_local", translate("Bind Local Only"))
o.description = translate("When selected, it can only be accessed locally. Recommended when using reverse proxies.")
o.default = 0
o.rmempty = true
o:depends("type", "vmess")
o:depends("type", "vless")
o:depends("type", "trojan")
o:depends("type", "shadowsocks")
o = s:option(Flag, "accept_lan", translate("Accept LAN Access"))
o.description = translate("When selected, it can be accessed from LAN. This may not be safe!")
o.default = 0
o.rmempty = true
o:depends("type", "vmess")
o:depends("type", "vless")
o:depends("type", "trojan")
o:depends("type", "shadowsocks")
return m
@@ -105,8 +105,13 @@ end
o.rmempty = false
o = sec:option(DummyValue, "type", translate("Server Type"))
function o.cfgvalue(...)
return Value.cfgvalue(...) or "ss"
function o.cfgvalue(self, section)
local val = Value.cfgvalue(self, section) or "ss"
if val == "vmess" then return "VMess (Xray)"
elseif val == "vless" then return "VLESS (Xray)"
elseif val == "trojan" then return "Trojan (Xray)"
elseif val == "shadowsocks" then return "Shadowsocks (Xray)"
else return val end
end
o = sec:option(DummyValue, "server_port", translate("Server Port"))
@@ -135,4 +140,4 @@ function o.cfgvalue(...)
return Value.cfgvalue(...) or "-"
end
return m
return m
@@ -985,6 +985,130 @@ start_dns() {
fi
}
# 生成 Xray 服务端配置
# 生成 Xray 服务端配置
generate_xray_config() {
local type="$1"
local port="$2"
local password="$3"
local security="$4"
local method="$5"
local network="$6"
local ws_path="$7"
local ws_host="$8"
local grpc_service="$9"
local alter_id="${10}"
local tcp_guise="${11}"
local tcp_guise_http_host="${12}"
local tcp_guise_http_path="${13}"
local config_file="${14}"
local inbound_json=""
case "$type" in
vmess)
inbound_json="{
\"protocol\": \"vmess\",
\"port\": $port,
\"settings\": {
\"clients\": [{\"id\": \"$password\", \"alterId\": $alter_id}]
},
\"streamSettings\": {
\"network\": \"$network\"
}
}"
;;
vless)
inbound_json="{
\"protocol\": \"vless\",
\"port\": $port,
\"settings\": {
\"clients\": [{\"id\": \"$password\"}],
\"decryption\": \"none\"
},
\"streamSettings\": {
\"network\": \"$network\"
}
}"
;;
trojan)
inbound_json="{
\"protocol\": \"trojan\",
\"port\": $port,
\"settings\": {
\"clients\": [{\"password\": \"$password\"}]
},
\"streamSettings\": {
\"network\": \"$network\"
}
}"
;;
shadowsocks)
inbound_json="{
\"protocol\": \"shadowsocks\",
\"port\": $port,
\"settings\": {
\"method\": \"$method\",
\"password\": \"$password\"
}
}"
;;
*)
return 1
;;
esac
# 添加传输层细节
case "$network" in
ws)
local ws_json="{\"path\": \"$ws_path\"}"
[ -n "$ws_host" ] && ws_json="{\"path\": \"$ws_path\", \"headers\": {\"Host\": \"$ws_host\"}}"
inbound_json=$(echo "$inbound_json" | sed "s/\"streamSettings\": {/\"streamSettings\": {\"wsSettings\": $ws_json, /")
;;
grpc)
[ -n "$grpc_service" ] && inbound_json=$(echo "$inbound_json" | sed "s/\"streamSettings\": {/\"streamSettings\": {\"grpcSettings\": {\"serviceName\": \"$grpc_service\"}, /")
;;
tcp)
# TCP HTTP 伪装
if [ "$tcp_guise" = "http" ]; then
local tcp_json="{\"header\": {\"type\": \"http\""
# 添加 HTTP Host
if [ -n "$tcp_guise_http_host" ]; then
# 将空格分隔的多个 host 转换为 JSON 数组格式
local host_list=$(echo "$tcp_guise_http_host" | sed 's/ /","/g')
tcp_json="$tcp_json, \"request\": {\"headers\": {\"Host\": [\"$host_list\"]}}"
fi
# 添加 HTTP Path
if [ -n "$tcp_guise_http_path" ]; then
local path_list=$(echo "$tcp_guise_http_path" | sed 's/ /","/g')
tcp_json="$tcp_json, \"response\": {\"headers\": {\"Location\": [\"$path_list\"]}}"
fi
tcp_json="$tcp_json}}"
inbound_json=$(echo "$inbound_json" | sed "s/\"streamSettings\": {/\"streamSettings\": {\"tcpSettings\": $tcp_json, /")
fi
;;
esac
cat > "$config_file" << EOF
{
"log": {
"loglevel": "warning"
},
"inbounds": [$inbound_json],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
]
}
EOF
return 0
}
gen_service_file() { #1-server.type 2-cfgname 3-file_path
local fastopen
if [ $(uci_get_by_name $2 fast_open) == "1" ]; then
@@ -1875,6 +1999,59 @@ start_server() {
ln_start_bin $(first_type microsocks) microsocks $listenip -p $(uci_get_by_name $1 server_port) -1 $auth_opts ssr-server$server_count
echolog "Server:Socks5 Server$server_count Started!"
;;
vmess|vless|trojan|shadowsocks)
# Xray 服务端支持
local port=$(uci_get_by_name "$1" server_port)
local uuid=$(uci_get_by_name "$1" uuid)
local trojan_pass=$(uci_get_by_name "$1" trojan_password)
local ss_pass=$(uci_get_by_name "$1" ss_password)
local security=$(uci_get_by_name "$1" security "auto")
local network=$(uci_get_by_name "$1" network "tcp")
local ws_path=$(uci_get_by_name "$1" ws_path "/")
local ws_host=$(uci_get_by_name "$1" ws_host "")
local grpc_service=$(uci_get_by_name "$1" grpc_service "")
local alter_id=$(uci_get_by_name "$1" alter_id "0")
local tcp_guise=$(uci_get_by_name "$1" tcp_guise "none")
local tcp_guise_http_host=$(uci_get_by_name "$1" tcp_guise_http_host "")
local tcp_guise_http_path=$(uci_get_by_name "$1" tcp_guise_http_path "")
# 确定密码/UUID
local password=""
local method=""
if [ "$type" = "vmess" ] || [ "$type" = "vless" ]; then
password="$uuid"
elif [ "$type" = "trojan" ]; then
password="$trojan_pass"
elif [ "$type" = "shadowsocks" ]; then
password="$ss_pass"
method="$security"
[ -z "$method" ] && method="chacha20-ietf-poly1305"
fi
[ -z "$password" ] && {
echolog "Server: $type 服务端缺少密码/UUID,跳过启动"
return 1
}
local config_file="$TMP_PATH/xray-server-$server_count.json"
# 生成 Xray 配置
generate_xray_config "$type" "$port" "$password" "$security" "$method" "$network" "$ws_path" "$ws_host" "$grpc_service" "$alter_id" "$tcp_guise" "$tcp_guise_http_host" "$tcp_guise_http_path" "$config_file"
if [ $? -ne 0 ]; then
echolog "Server: Xray $type 配置生成失败"
return 1
fi
local xray_bin=$(first_type xray)
if [ -z "$xray_bin" ]; then
echolog "Server: xray-core 未安装,无法启动 $type 服务端"
return 1
fi
ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file"
echolog "Server: Xray $type 服务端 Server$server_count 已启动 (端口: $port)"
;;
esac
server_port=$(uci_get_by_name $1 server_port)
if [ "$USE_TABLES" = "nftables" ]; then
+1 -1
View File
@@ -114,7 +114,7 @@ while [ "1" == "1" ]; do #死循环
fi
#server
if [ "$server_process_count" -gt 0 ]; then
icount=$(match_proc_count 'ssr-server|ss-server-')
icount=$(match_proc_count 'ssr-server|ss-server-|xray-server-')
if [ "$icount" -lt "$server_process_count" ]; then #如果进程挂掉就重启它
logger -t "$NAME" "ssrplus server error.restart!"
echolog "ssrplus server error.restart!"