#!/bin/sh NAME=bypass S=/usr/share/$NAME uci_get_by_name(){ w=$(uci -q get $NAME.$1.$2) echo ${w:=$3} } uci_get_by_type(){ w=$(uci -q get $NAME.@$1[0].$2) echo ${w:=$3} } log(){ echo "$(date +'%Y-%m-%d %H:%M:%S') By-Switch : $*" >> /tmp/log/$NAME.log } get_ip(){ if ! echo $ip | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null;then r=1 while ! nslookup $ip 127.0.0.1#5336 >/dev/null 2>&1;do [ $r -ge 10 ] && return 1 || let r++ sleep 1 done ip=$(nslookup $ip 127.0.0.1#5336 2>/dev/null | grep Address | awk -F' ' '{print$NF}' | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$");i=$? ip=$(echo "$ip" | sed -n 1p) fi return $i } f_bin(){ case $1 in ss)w=$(which ss-local);; ssr)w=$(which ssr-local);; vmess|vless)w=$(which xray);; trojan)w=$(which trojan-plus);; trojan-go)w=$(which trojan-go);; naiveproxy)w=$(which naive);; esac echo ${w:=0} } gen_port(){ lport=1090 while [ $(netstat -tln | grep -c :$lport) != 0 ];do let lport++;done } gen_config_file(){ pass=$(uci_get_by_name $1 password) timeout=$(uci_get_by_name $1 timeout 60) [ $(uci_get_by_name $1 fast_open 0) = 1 ] && fast=true || fast=false case $type in ss) cat <<-EOF > $J { "server":"$ip", "server_port":$port, "local_address":"0.0.0.0", "local_port":$lport, "password":"$pass", "timeout":$timeout, "method":"$(uci_get_by_name $1 encrypt_method_ss)", "reuse_port":true, "fast_open":$fast } EOF plugin=$(uci_get_by_name $1 plugin 0) if [ $plugin != 0 -a -x "$(which $plugin)" ];then sed -i "s@$ip\",@$ip\",\n\"plugin\":\"$plugin\",\n\"plugin_opts\":\"$(uci_get_by_name $1 plugin_opts)\",@" $J fi;; ssr) cat <<-EOF > $J { "server":"$ip", "server_port":$port, "local_address":"0.0.0.0", "local_port":$lport, "password":"$pass", "timeout":$timeout, "method":"$(uci_get_by_name $1 encrypt_method)", "protocol":"$(uci_get_by_name $1 protocol)", "protocol_param":"$(uci_get_by_name $1 protocol_param)", "obfs":"$(uci_get_by_name $1 obfs)", "obfs_param":"$(uci_get_by_name $1 obfs_param)", "reuse_port":true, "fast_open":$fast } EOF ;; naiveproxy) cat <<-EOF > $J { "listen":"socks://0.0.0.0:$lport", "proxy":"https://$(uci_get_by_name $1 username):$pass@$(uci_get_by_name $1 server):$port", "concurrency":"${3:-1}" } EOF ;; esac } curl_check(){ if [ $(uci_get_by_name $1 kcp_enable 0) = 1 ];then log "Skip KCPTUN Node!";return 1 fi type=$(uci_get_by_name $1 type) if [ $type = tun ];then curl --interface $(uci_get_by_name $1 iface br-lan) --resolve dns.google:443:8.8.8.8 -so /dev/null --connect-timeout 20 https://dns.google;return $? elif [ $type != socks5 ];then cmd=$(f_bin $type) if [ ! -x $cmd ];then [ $type = ss -o $type = ssr ] && type=$type-local log "Can't find $(echo $type) program, Skip this Node($($UCI$1.alias || uci_get_by_name $1 server))." return 1 fi fi gen_port J=/var/etc/$NAME/by-socks5-check.json gen_config_file $1 IP=127.0.0.1 param= case $type in ss|ssr) $cmd -c $J >/dev/null 2>&1 &;; vmess|vless) $S/genv2config $1 tcp 0 $lport $ip > $J sed -i 's/\\//g' $J $cmd -c $J >/dev/null 2>&1 &;; trojan|trojan-go) $S/gentrojanconfig $1 client $lport $ip > $J sed -i 's/\\//g' $J $cmd --config $J >/dev/null 2>&1 &;; naiveproxy) $cmd $J 2>&1 &;; socks5)IP=$ip if [ $(uci_get_by_name $1 auth_enable 0) = 1 ];then username=$(uci_get_by_name $1 username) if [ -n "$username" ];then param="-U $username:$(uci_get_by_name $1 password)" else return 1 fi fi;; esac r=1 while [ $(netstat -tlnp | grep ${cmd##*/} | grep -c :$lport) = 0 ];do [ $r -ge 10 ] && return 1 || let r++ sleep 1 done curl -x socks5://$IP:$lport $param --resolve dns.google:443:8.8.8.8 -so /dev/null --connect-timeout 20 https://dns.google;i=$? kill -9 $(ps -w | grep $J | grep -v grep | awk '{print$1}') 2>/dev/null rm -f $J [ $i = 0 ] || log "Server : $($UCI$1.alias || uci_get_by_name $1 server) cURL check error, Try to switch another server." return $i } test_proxy(){ ip=$(uci_get_by_name $1 server) get_ip || return 1 port=$(uci_get_by_name $1 server_port) ipset add ss_spec_wan_ac $ip 2>/dev/null a=$? b=$(tcping -c $time_b -i 1 -t 2 -p $port $ip 2>/dev/null | grep 'failed' | awk -F ',' '{print$3}' | awk -F . '{print$1}') if [ -z "$b" -o "$b" -gt 50 ];then b=1 else curl_check $1;b=$? fi [ $a = 0 ] && ipset del ss_spec_wan_ac $ip 2>/dev/null return $b } check_proxy(){ for i in $(seq 1 $(uci_get_by_type global switch_try_count 3));do curl -so /dev/null --connect-timeout $time_b https://www.google.com && return 0 curl -so /dev/null --connect-timeout $time_b https://www.baidu.com && a=1 || a=2 sleep 1 done return $a } select_proxy(){ SERVER_C=0 a=$(uci -X show $NAME | grep =servers) b=$(echo "$a" | wc -l) [ $c -ge $b ] && c=1 for i in $(seq $c $b);do d=$(echo "$a" | sed 's/.*\.\(.*\)=.*/\1/' | sed -n ${i}p) ([ $d = $SERVER_B ] || [ $(uci_get_by_name $d switch_enable 0) != 1 ]) && continue ip=$(uci_get_by_name $d server) get_ip || continue port=$(uci_get_by_name $d server_port) ipset add ss_spec_wan_ac $ip 2>/dev/null x=$? $S/by-check $ip $port $time_b && curl_check $d y=$? [ $x = 0 ] && ipset del ss_spec_wan_ac $ip 2>/dev/null if [ $y = 0 ];then SERVER_C=$d c=$i return 0 fi done } switch_proxy(){ /etc/init.d/$NAME restart $SERVER_B } [ "$1" = start ] || exit 1 SERVER_A=$(uci_get_by_type global global_server) SERVER_B=$SERVER_A [ $(uci_get_by_name $SERVER_A kcp_enable 0) = 1 ] && exit 1 c=1 time_a=$(uci_get_by_type global switch_time 300) time_b=$(uci_get_by_type global switch_timeout 5) UCI="uci -q get $NAME." sleep 10 while :;do if [ $SERVER_A != $SERVER_B ];then log "Current server : $($UCI$SERVER_B.alias || uci_get_by_name $SERVER_B server) is not main server, Try to switch back to $($UCI$SERVER_A.alias || uci_get_by_name $SERVER_A server)." if test_proxy $SERVER_A;then log "Main server is available. Switch to main server." SERVER_B=$SERVER_A switch_proxy continue else log "Main server is not available. Continue using current server." fi fi check_proxy a=$? if [ $a = 1 ];then log "Current server : $($UCI$SERVER_B.alias || uci_get_by_name $SERVER_B server) error.Try to switch another server." select_proxy if [ $SERVER_C != 0 ];then log "Another server : $($UCI$SERVER_C.alias || uci_get_by_name $SERVER_C server) is available.Now switching server." SERVER_B=$SERVER_C switch_proxy else log "No server available. Try restart current server." switch_proxy fi elif [ $a = 2 ];then log "Network Problem. Do nothing." fi sleep $time_a done