update 2026-05-10 09:48:30

This commit is contained in:
action committed 2026-05-10 09:48:30 +08:00
1 parent 95ac96413e
commit 0b362674f1
6244 files changed
+2992248

No files matched your search

+225
View File
@@ -0,0 +1,225 @@
#!/bin/sh
#
# Copyright (C) 2017 openwrt-ssr
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
. $IPKG_INSTROOT/etc/init.d/shadowsocksr
LOCK_FILE="/var/lock/ssr-monitor.lock"
[ -f "$LOCK_FILE" ] && exit 2
touch "$LOCK_FILE"
ps_list() {
if busybox ps -w >/dev/null 2>&1; then
busybox ps -w
else
busybox ps
fi
}
match_proc_count() {
local pattern="$1"
ps_list | grep -E "$pattern" | grep -v grep | wc -l
}
redir_tcp_running() {
local ssr_count
local ipt_count
ssr_count=$(match_proc_count 'ssr-retcp')
ipt_count=$(ps_list | grep 'ipt2socks' | grep -v grep | grep -E ' -T( |$)| --tcp-only( |$)' | wc -l)
echo $((ssr_count + ipt_count))
}
redir_udp_running() {
local ssr_count
local ipt_count
ssr_count=$(match_proc_count 'ssr-reudp')
ipt_count=$(ps_list | grep 'ipt2socks' | grep -v grep | grep -E ' -U( |$)| --udp-only( |$)' | wc -l)
echo $((ssr_count + ipt_count))
}
kill_matched_procs() {
local pattern="$1"
ps_list | grep -E "$pattern" | grep -v grep | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
}
get_expected_threads() {
local threads
threads=$(uci_get_by_type global threads 0)
if [ "$threads" = "0" ] || [ -z "$threads" ]; then
threads=$(grep -c '^processor' /proc/cpuinfo 2>/dev/null)
fi
case "$threads" in
''|*[!0-9]*)
threads=1
;;
esac
[ "$threads" -lt 1 ] && threads=1
echo "$threads"
}
server_process_count=$1
redir_tcp_process=$2
redir_udp_process=$3
kcp_process=$4
local_process=$5
pdnsd_process=$6
if [ -z "$pdnsd_process" ]; then
pdnsd_process=0
fi
i=0
GLOBAL_SERVER=$(uci_get_by_type global global_server)
GLOBAL_TYPE=$(uci_get_by_name $GLOBAL_SERVER type)
EXPECTED_THREADS=$(get_expected_threads)
server=$(uci_get_by_name $GLOBAL_SERVER server)
kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port)
server_port=$(uci_get_by_name $GLOBAL_SERVER server_port)
password=$(uci_get_by_name $GLOBAL_SERVER kcp_password)
kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param)
[ "$password" != "" ] && password="--key "${password}
while [ "1" == "1" ]; do #死循环
sleep 000030s
#redir tcp
if [ "$redir_tcp_process" -gt 0 ]; then
icount=$(redir_tcp_running)
local tcp_expected="$redir_tcp_process"
if [ "$GLOBAL_TYPE" = "socks5" ]; then
tcp_expected="$EXPECTED_THREADS"
fi
if [ "$icount" -lt "$tcp_expected" ]; then
logger -t "$NAME" "ssrplus redir tcp error.restart!"
echolog "ssrplus redir tcp error.restart!"
/etc/init.d/shadowsocksr restart
exit 0
fi
fi
#redir udp
if [ "$redir_udp_process" -gt 0 ]; then
icount=$(redir_udp_running)
local udp_expected="$redir_udp_process"
if [ "$GLOBAL_TYPE" = "socks5" ]; then
udp_expected="$EXPECTED_THREADS"
fi
if [ "$icount" -lt "$udp_expected" ]; then
logger -t "$NAME" "ssrplus redir udp error.restart!"
echolog "ssrplus redir udp error.restart!"
/etc/init.d/shadowsocksr restart
exit 0
fi
fi
#server
if [ "$server_process_count" -gt 0 ]; then
icount=$(match_proc_count 'ssr-server|ss-server-')
if [ "$icount" -lt "$server_process_count" ]; then #如果进程挂掉就重启它
logger -t "$NAME" "ssrplus server error.restart!"
echolog "ssrplus server error.restart!"
kill_matched_procs 'ssr-server|ss-server-'
/etc/init.d/shadowsocksr restart
exit 0
fi
fi
#kcptun
if [ "$kcp_process" -gt 0 ]; then
icount=$(ps_list | grep kcptun-client | grep -v grep | wc -l)
if [ "$icount" -lt "$kcp_process" ]; then #如果进程挂掉就重启它
logger -t "$NAME" "ssrplus kcptun error.restart!"
echolog "ssrplus kcptun error.restart!"
killall -q -9 kcptun-client
(/usr/bin/kcptun-client -r $server:$kcp_port -l :$server_port $password $kcp_param &)
fi
fi
#localsocks
if [ "$local_process" -gt 0 ]; then
icount=$(match_proc_count 'ssr-local|ss-local|tuic-local')
if [ "$icount" -lt "$local_process" ]; then #如果进程挂掉就重启它
logger -t "$NAME" "global socks server error.restart!"
echolog "global socks server error.restart!"
kill_matched_procs 'ssr-local|ss-local|tuic-local'
/etc/init.d/shadowsocksr restart
exit 0
fi
fi
#dns2tcp
if [ "$pdnsd_process" -eq 1 ]; then
icount=$(ps_list | grep $TMP_BIN_PATH/dns2tcp | grep -v grep | wc -l)
if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它
logger -t "$NAME" "dns2tcp tunnel error.restart!"
echolog "dns2tcp tunnel error.restart!"
dnsserver=$(uci_get_by_type global tunnel_forward 8.8.4.4:53)
kill -9 $(ps_list | grep $TMP_BIN_PATH/dns2tcp | grep -v grep | awk '{print $1}') >/dev/null 2>&1
start_dns2tcp "$dnsserver"
fi
#mosdns
elif [ "$pdnsd_process" -eq 4 ]; then
icount=$(ps_list | grep $TMP_BIN_PATH/mosdns | grep -v grep | wc -l)
if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它
logger -t "$NAME" "mosdns tunnel error.restart!"
echolog "mosdns tunnel error.restart!"
dnsserver=$(uci_get_by_type global tunnel_forward 8.8.4.4:53)
kill -9 $(ps_list | grep $TMP_BIN_PATH/mosdns | grep -v grep | awk '{print $1}') >/dev/null 2>&1
ln_start_bin $(first_type mosdns) mosdns start -c /etc/mosdns/config.yaml
fi
#chinadns-ng(proxy)
elif [ "$pdnsd_process" -eq 6 ]; then
icount=$(ps_list | grep -e ssrplus-dns -e "chinadns-ng -b 127.0.0.1 -l $tmp_dns_port" | grep -v grep | wc -l)
if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它
logger -t "$NAME" "chinadns-ng $dnsserver tunnel error.restart!"
echolog "chinadns-ng $dnsserver tunnel error.restart!"
dnsserver=$(uci_get_by_type global chinadns_ng_tunnel_forward 8.8.4.4:53)
kill -9 $(ps_list | grep "chinadns-ng -b 127.0.0.1 -l $tmp_dns_port" | grep -v grep | awk '{print $1}') >/dev/null 2>&1
local chinadns_ng_proto="$(uci_get_by_type global chinadns_ng_proto)"
local chinadns_ng_dns=""
IFS=','
for chinadns_ng_server in $dnsserver; do
local chinadns_ng_ip="${chinadns_ng_server%%:*}"
local chinadns_ng_port="${chinadns_ng_server##*:}"
[ "$chinadns_ng_ip" = "$chinadns_ng_port" ] && chinadns_ng_port="53"
chinadns_ng_tls_port="853"
case "$chinadns_ng_proto" in
"none")
chinadns_ng_server="${chinadns_ng_ip}#${chinadns_ng_port}"
;;
"tls")
chinadns_ng_server="${chinadns_ng_proto}://${chinadns_ng_ip}#${chinadns_ng_tls_port}"
;;
*)
chinadns_ng_server="${chinadns_ng_proto}://${chinadns_ng_ip}#${chinadns_ng_port}"
;;
esac
chinadns_ng_dns="${chinadns_ng_dns} -t ${chinadns_ng_server}"
done
unset IFS
dnsserver="$chinadns_ng_dns"
ln_start_bin $(first_type chinadns-ng) chinadns-ng -b 127.0.0.1 -l $tmp_dns_port -l $dns_port -p 3 -d gfw $dnsserver -N --filter-qtype 64,65 -f -r --cache 4096 --cache-stale 86400 --cache-refresh 20
fi
#built-in dns
elif [ "$pdnsd_process" -eq 7 ]; then
if ! is_builtin_dns_active; then
logger -t "$NAME" "builtin dns error.restart!"
echolog "builtin dns error.restart!"
/etc/init.d/shadowsocksr restart
exit 0
fi
fi
#chinadns-ng(china)
if [ "$(uci -q get "dhcp.@dnsmasq[0]._unused_ssrp_changed")" = "1" ]; then
icount=$(ps_list | grep $TMP_BIN_PATH/chinadns-ng | grep -v grep | wc -l)
if [ "$icount" -lt 1 ]; then #如果进程挂掉就重启它
logger -t "$NAME" "chinadns-ng tunnel error.restart!"
echolog "chinadns-ng tunnel error.restart!"
chinadns=$(uci_get_by_type global chinadns_forward)
wandns="$(ifstatus wan | jsonfilter -e '@["dns-server"][0]' || echo "119.29.29.29")"
case "$chinadns" in
"wan") chinadns="$wandns" ;;
""|"wan_114") chinadns="$wandns,114.114.114.114" ;;
esac
kill -9 $(ps_list | grep $TMP_BIN_PATH/chinadns-ng | grep -v grep | awk '{print $1}') >/dev/null 2>&1
ln_start_bin $(first_type chinadns-ng) chinadns-ng -l $china_dns_port -4 china -p 3 -c ${chinadns/:/#} -t 127.0.0.1#$dns_port -N -f -r
fi
fi
done
File diff suppressed because it is too large. Load diff
+282
View File
@@ -0,0 +1,282 @@
#!/bin/sh
#
# Copyright (C) 2017 openwrt-ssr
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
ORIG_ARG1="${1:-}"
ORIG_ARG2="${2:-}"
ORIG_ARG3="${3:-}"
[ -f /lib/functions.sh ] && . /lib/functions.sh
. $IPKG_INSTROOT/etc/init.d/shadowsocksr
LOCK_FILE="/var/lock/ssr-switch.lock"
PROBE_SID=""
cycle_time=60
switch_time=3
probe_socks_port=10800
direct_fail_count=0
direct_fail_limit=3
probe_url="$(uci_get_by_type server_subscribe url_test_url)"
[ -n "$probe_url" ] || probe_url="https://www.google.com/generate_204"
PROBE_INSTANCE_KEY="ssr-switch-probe-local"
DEFAULT_SERVER="$(uci_get_by_type global global_server)"
CURRENT_SERVER="$DEFAULT_SERVER"
ENABLE_SERVER="nil"
cleanup_probe_socks() {
ps_list | grep -v "grep" | grep -E "tcp-http-ssr-switch-local\\.json|ss-${PROBE_INSTANCE_KEY}/config\\.yaml|tuic-${PROBE_INSTANCE_KEY}/config\\.yaml" | awk '{print $1}' | xargs kill >/dev/null 2>&1
sleep 1
ps_list | grep -v "grep" | grep -E "tcp-http-ssr-switch-local\\.json|ss-${PROBE_INSTANCE_KEY}/config\\.yaml|tuic-${PROBE_INSTANCE_KEY}/config\\.yaml" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
rm -f "$TMP_PATH/tcp-http-ssr-switch-local.json" 2>/dev/null
rm -rf "$TMP_PATH/ss-${PROBE_INSTANCE_KEY}" "$TMP_PATH/tuic-${PROBE_INSTANCE_KEY}" 2>/dev/null
rm -f /tmp/ssr-switch-probe.log 2>/dev/null
}
start_probe_socks() {
local sid="$1"
local server_type
server_type="$(uci_get_by_name "$sid" type)"
[ "$server_type" = "clash" ] && return 1
[ "$server_type" = "tuic" ] && return 1
[ "$server_type" = "socks5" ] && return 1
cleanup_probe_socks
LOCAL_SERVER="$sid"
local_config_file="$TMP_PATH/tcp-http-ssr-switch-local.json"
_local="2"
local_enable=0
tmp_local_port=
mode="tcp,udp"
if [ "$server_type" = "v2ray" ]; then
export SSR_SWITCH_PROBE=1
gen_config_file "$LOCAL_SERVER" "$server_type" 4 0 "$probe_socks_port" >/tmp/ssr-switch-probe.log 2>&1 || return 1
unset SSR_SWITCH_PROBE
local xray_bin
xray_bin="$(first_type xray)"
[ -x "$xray_bin" ] || return 1
"$xray_bin" run -c "$local_config_file" >>/tmp/ssr-switch-probe.log 2>&1 &
else
export SSR_SWITCH_PROBE=1
export SSR_SWITCH_PROBE_INSTANCE_KEY="$PROBE_INSTANCE_KEY"
start_local_with_port "$probe_socks_port" >/tmp/ssr-switch-probe.log 2>&1 || return 1
unset SSR_SWITCH_PROBE_INSTANCE_KEY
unset SSR_SWITCH_PROBE
fi
sleep 2
return 0
}
probe_http_ok() {
case "$1" in
[1-5][0-9][0-9])
return 0
;;
esac
return 1
}
check_direct_probe() {
local code
code="$(curl -k -sS -L -o /dev/null \
--connect-timeout "$switch_time" \
--max-time "$switch_time" \
-w '%{http_code}' \
"$probe_url" 2>/dev/null || true)"
probe_http_ok "$code"
}
check_proxy_via_socks() {
local try_count
local code
local proxy_host
try_count="$(uci_get_by_type global switch_try_count 3)"
for i in $(seq 1 "$try_count"); do
for proxy_host in "127.0.0.1:$probe_socks_port" "[::1]:$probe_socks_port"; do
code="$(curl -k -sS -L -o /dev/null \
--connect-timeout "$switch_time" \
--max-time "$switch_time" \
--socks5-hostname "$proxy_host" \
-w '%{http_code}' \
"$probe_url" 2>/dev/null || true)"
probe_http_ok "$code" && return 0
done
sleep 1
done
return 1
}
test_proxy() {
local sid="$1"
[ "$(uci_get_by_name "$sid" type)" = "clash" ] && return 1
[ "$(uci_get_by_name "$sid" type)" = "tuic" ] && return 1
start_probe_socks "$sid" || {
cleanup_probe_socks
return 1
}
check_proxy_via_socks
local ret=$?
cleanup_probe_socks
return $ret
}
search_proxy() {
local sid="$1"
[ "$(uci_get_by_name "$sid" switch_enable 0)" = "1" ] || return 1
[ "$(uci_get_by_name "$sid" type)" = "clash" ] && return 1
[ "$(uci_get_by_name "$sid" type)" = "tuic" ] && return 1
[ "$sid" = "$CURRENT_SERVER" ] && return 1
[ "$ENABLE_SERVER" != "nil" ] && return 0
if test_proxy "$sid"; then
ENABLE_SERVER="$sid"
return 0
fi
return 1
}
select_proxy() {
config_load "$NAME"
ENABLE_SERVER="nil"
config_foreach search_proxy servers
}
set_main_server() {
local sid="$1"
[ -n "$sid" ] || return 1
uci set shadowsocksr.@global[0].global_server="$sid"
uci commit shadowsocksr
return 0
}
switch_proxy() {
set_main_server "$1" || return 1
/etc/init.d/shadowsocksr restart "$1"
return 0
}
start() {
while [ "1" = "1" ]; do
sleep "0000$cycle_time"
run_once
done
}
run_once() {
DEFAULT_SERVER="$(uci_get_by_type global global_server)"
[ "$DEFAULT_SERVER" = "nil" ] && {
direct_fail_count=0
return 0
}
[ "$(uci_get_by_name "$DEFAULT_SERVER" type)" = "clash" ] && {
direct_fail_count=0
cleanup_probe_socks
return 0
}
[ "$(uci_get_by_name "$DEFAULT_SERVER" type)" = "tuic" ] && {
direct_fail_count=0
cleanup_probe_socks
return 0
}
[ "$(uci_get_by_name "$DEFAULT_SERVER" kcp_enable 0)" = "1" ] && {
direct_fail_count=0
cleanup_probe_socks
return 1
}
CURRENT_SERVER="$DEFAULT_SERVER"
if check_direct_probe; then
direct_fail_count=0
return 0
fi
direct_fail_count=$((direct_fail_count + 1))
[ "$direct_fail_count" -lt "$direct_fail_limit" ] && return 0
direct_fail_count=0
if test_proxy "$CURRENT_SERVER"; then
return 0
fi
echolog "Current server error, try to switch another server."
select_proxy
if [ "$ENABLE_SERVER" != "nil" ]; then
CURRENT_SERVER="$ENABLE_SERVER"
switch_proxy "$CURRENT_SERVER"
echolog "Switch to $(uci_get_by_name "$CURRENT_SERVER" alias) proxy!"
else
switch_proxy "$CURRENT_SERVER"
echolog "Try restart current server."
fi
return 0
}
probe_once() {
local sid="$1"
[ -n "$sid" ] || {
echo "missing_sid"
return 1
}
cleanup_probe_socks
if ! start_probe_socks "$sid"; then
echo "probe_start:fail"
return 1
fi
echo "probe_start:ok"
echo "probe:curl_ipv4"
curl -k -sS -L -o /dev/null \
--connect-timeout "$switch_time" \
--max-time "$switch_time" \
--socks5-hostname "127.0.0.1:$probe_socks_port" \
-w 'code=%{http_code}\n' \
"$probe_url" 2>/dev/null || true
echo "probe:curl_ipv6"
curl -g -k -sS -L -o /dev/null \
--connect-timeout "$switch_time" \
--max-time "$switch_time" \
--socks5-hostname "[::1]:$probe_socks_port" \
-w 'code=%{http_code}\n' \
"$probe_url" 2>/dev/null || true
cleanup_probe_socks
return 0
}
main() {
case "${ORIG_ARG1:-}" in
probe)
PROBE_SID="${ORIG_ARG2:-}"
probe_once "$PROBE_SID"
;;
once)
run_once
;;
start)
[ -n "$ORIG_ARG2" ] && cycle_time="$ORIG_ARG2"
[ -n "$ORIG_ARG3" ] && switch_time="$ORIG_ARG3"
[ -f "$LOCK_FILE" ] && exit 2
touch "$LOCK_FILE"
start
;;
*)
[ -n "$ORIG_ARG1" ] && cycle_time="$ORIG_ARG1"
[ -n "$ORIG_ARG2" ] && switch_time="$ORIG_ARG2"
[ -f "$LOCK_FILE" ] && exit 2
touch "$LOCK_FILE"
start
;;
esac
}
if [ "${0##*/}" = "ssr-switch" ]; then
main "$@"
fi