mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-07-28 01:11:21 +08:00
275 lines
6.5 KiB
Bash
Executable File
275 lines
6.5 KiB
Bash
Executable File
#!/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|v2ray-${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|v2ray-${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}" "$TMP_PATH/v2ray-${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"
|
|
|
|
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
|
|
local rc=$?
|
|
unset SSR_SWITCH_PROBE_INSTANCE_KEY
|
|
unset SSR_SWITCH_PROBE
|
|
[ "$rc" = "0" ] || return 1
|
|
|
|
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
|