1430 lines
50 KiB
Bash
Executable File
1430 lines
50 KiB
Bash
Executable File
#!/bin/sh
|
||
# Copyright (C) 2018-2020 L-WRT Team
|
||
# Copyright (C) 2021 xiaorouji
|
||
|
||
. $IPKG_INSTROOT/lib/functions.sh
|
||
. $IPKG_INSTROOT/lib/functions/service.sh
|
||
|
||
CONFIG=passwall
|
||
TMP_PATH=/var/etc/$CONFIG
|
||
TMP_BIN_PATH=$TMP_PATH/bin
|
||
TMP_ID_PATH=$TMP_PATH/id
|
||
TMP_PORT_PATH=$TMP_PATH/port
|
||
TMP_ROUTE_PATH=$TMP_PATH/route
|
||
LOCK_FILE=/var/lock/$CONFIG.lock
|
||
LOG_FILE=/var/log/$CONFIG.log
|
||
APP_PATH=/usr/share/$CONFIG
|
||
RULES_PATH=/usr/share/${CONFIG}/rules
|
||
TMP_DNSMASQ_PATH=/var/etc/dnsmasq-passwall.d
|
||
DNSMASQ_PATH=/etc/dnsmasq.d
|
||
LOCAL_DOH_PORT=7912
|
||
DNS_PORT=7913
|
||
TUN_DNS="127.0.0.1#${DNS_PORT}"
|
||
IS_DEFAULT_DNS=0
|
||
LOCAL_DNS=
|
||
DEFAULT_DNS=
|
||
NO_PROXY=
|
||
use_tcp_node_resolve_dns=0
|
||
use_udp_node_resolve_dns=0
|
||
LUA_API_PATH=/usr/lib/lua/luci/model/cbi/$CONFIG/api
|
||
API_GEN_SS=$LUA_API_PATH/gen_shadowsocks.lua
|
||
API_GEN_XRAY=$LUA_API_PATH/gen_xray.lua
|
||
API_GEN_XRAY_PROTO=$LUA_API_PATH/gen_xray_proto.lua
|
||
API_GEN_TROJAN=$LUA_API_PATH/gen_trojan.lua
|
||
API_GEN_NAIVE=$LUA_API_PATH/gen_naiveproxy.lua
|
||
echolog() {
|
||
local d="$(date "+%Y-%m-%d %H:%M:%S")"
|
||
echo -e "$d: $*" >>$LOG_FILE
|
||
}
|
||
|
||
config_n_get() {
|
||
local ret=$(uci -q get "${CONFIG}.${1}.${2}" 2>/dev/null)
|
||
echo "${ret:=$3}"
|
||
}
|
||
|
||
config_t_get() {
|
||
local index=${4:-0}
|
||
local ret=$(uci -q get "${CONFIG}.@${1}[${index}].${2}" 2>/dev/null)
|
||
echo "${ret:=${3}}"
|
||
}
|
||
|
||
set_lock(){
|
||
exec 1000>"$LOCK_FILE"
|
||
flock -x 1000
|
||
}
|
||
|
||
trap 'rm -f "$LOCK_FILE"; exit $?' INT TERM EXIT
|
||
|
||
unlock() {
|
||
failcount=1
|
||
while [ "$failcount" -le 10 ]; do
|
||
if [ -f "$LOCK_FILE" ]; then
|
||
let "failcount++"
|
||
sleep 1s
|
||
[ "$failcount" -ge 10 ] && unset_lock
|
||
else
|
||
break
|
||
fi
|
||
done
|
||
}
|
||
|
||
unset_lock(){
|
||
flock -u 1000
|
||
rm -rf "$LOCK_FILE"
|
||
}
|
||
|
||
_exit()
|
||
{
|
||
local rc=$1
|
||
unset_lock
|
||
exit ${rc}
|
||
}
|
||
|
||
get_enabled_anonymous_secs() {
|
||
uci -q show "${CONFIG}" | grep "${1}\[.*\.enabled='1'" | cut -d '.' -sf2
|
||
}
|
||
|
||
get_host_ip() {
|
||
local host=$2
|
||
local count=$3
|
||
[ -z "$count" ] && count=3
|
||
local isip=""
|
||
local ip=$host
|
||
if [ "$1" == "ipv6" ]; then
|
||
isip=$(echo $host | grep -E "([[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,7}::[a-f0-9]{0,4}(:[a-f0-9]{1,4}){0,7}])")
|
||
if [ -n "$isip" ]; then
|
||
isip=$(echo $host | cut -d '[' -f2 | cut -d ']' -f1)
|
||
else
|
||
isip=$(echo $host | grep -E "([a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,7}::[a-f0-9]{0,4}(:[a-f0-9]{1,4}){0,7})")
|
||
fi
|
||
else
|
||
isip=$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}")
|
||
fi
|
||
[ -z "$isip" ] && {
|
||
local t=4
|
||
[ "$1" == "ipv6" ] && t=6
|
||
local vpsrip=$(resolveip -$t -t $count $host | awk 'NR==1{print}')
|
||
ip=$vpsrip
|
||
}
|
||
echo $ip
|
||
}
|
||
|
||
get_node_host_ip() {
|
||
local ip
|
||
local address=$(config_n_get $1 address)
|
||
[ -n "$address" ] && {
|
||
local use_ipv6=$(config_n_get $1 use_ipv6)
|
||
local network_type="ipv4"
|
||
[ "$use_ipv6" == "1" ] && network_type="ipv6"
|
||
ip=$(get_host_ip $network_type $address)
|
||
}
|
||
echo $ip
|
||
}
|
||
|
||
get_ip_port_from() {
|
||
local __host=${1}; shift 1
|
||
local __ipv=${1}; shift 1
|
||
local __portv=${1}; shift 1
|
||
|
||
local val1 val2
|
||
val2=$(echo $__host | sed -n 's/^.*[:#]\([0-9]*\)$/\1/p')
|
||
val1="${__host%%${val2:+[:#]${val2}*}}"
|
||
eval "${__ipv}=\"$val1\"; ${__portv}=\"$val2\""
|
||
}
|
||
|
||
host_from_url(){
|
||
local f=${1}
|
||
|
||
## Remove protocol part of url ##
|
||
f="${f##http://}"
|
||
f="${f##https://}"
|
||
f="${f##ftp://}"
|
||
f="${f##sftp://}"
|
||
|
||
## Remove username and/or username:password part of URL ##
|
||
f="${f##*:*@}"
|
||
f="${f##*@}"
|
||
|
||
## Remove rest of urls ##
|
||
f="${f%%/*}"
|
||
echo "${f%%:*}"
|
||
}
|
||
|
||
hosts_foreach() {
|
||
local __hosts
|
||
eval "__hosts=\$${1}"; shift 1
|
||
local __func=${1}; shift 1
|
||
local __default_port=${1}; shift 1
|
||
local __ret=1
|
||
|
||
[ -z "${__hosts}" ] && return 0
|
||
local __ip __port
|
||
for __host in $(echo $__hosts | sed 's/[ ,]/\n/g'); do
|
||
get_ip_port_from "$__host" "__ip" "__port"
|
||
eval "$__func \"${__host}\" \"\${__ip}\" \"\${__port:-${__default_port}}\" \"$@\""
|
||
__ret=$?
|
||
[ ${__ret} -ge ${ERROR_NO_CATCH:-1} ] && return ${__ret}
|
||
done
|
||
}
|
||
|
||
get_first_dns() {
|
||
local __hosts_val=${1}; shift 1
|
||
__first() {
|
||
[ -z "${2}" ] && return 0
|
||
echo "${2}#${3}"
|
||
return 1
|
||
}
|
||
eval "hosts_foreach \"${__hosts_val}\" __first \"$@\""
|
||
}
|
||
|
||
get_last_dns() {
|
||
local __hosts_val=${1}; shift 1
|
||
local __first __last
|
||
__every() {
|
||
[ -z "${2}" ] && return 0
|
||
__last="${2}#${3}"
|
||
__first=${__first:-${__last}}
|
||
}
|
||
eval "hosts_foreach \"${__hosts_val}\" __every \"$@\""
|
||
[ "${__first}" == "${__last}" ] || echo "${__last}"
|
||
}
|
||
|
||
gen_dnsmasq_items() {
|
||
local ipsetlist=${1}; shift 1
|
||
local fwd_dns=${1}; shift 1
|
||
local outf=${1}; shift 1
|
||
|
||
awk -v ipsetlist="${ipsetlist}" -v ipsetoutf="${TMP_DNSMASQ_PATH}/ipset.conf" -v fwd_dns="${fwd_dns}" -v outf="${outf}" '
|
||
BEGIN {
|
||
if(outf == "") {outf="/dev/stdout"; ipsetoutf="/dev/stdout";}
|
||
split(fwd_dns, dns, ","); setdns=length(dns)>0; setlist=length(ipsetlist)>0;
|
||
if(setdns) for(i in dns) if(length(dns[i])==0) delete dns[i];
|
||
fail=1;
|
||
}
|
||
! /^$/&&!/^#/ {
|
||
fail=0
|
||
if(! (setdns || setlist)) {printf("server=%s\n", $0) >>outf; next;}
|
||
if(setdns) for(i in dns) printf("server=/.%s/%s\n", $0, dns[i]) >>outf;
|
||
|
||
if(setlist) printf("ipset=/.%s/%s\n", $0, ipsetlist) >>ipsetoutf;
|
||
}
|
||
END {fflush(outf); close(outf); fflush(ipsetoutf); close(ipsetoutf); exit(fail);}
|
||
'
|
||
}
|
||
|
||
gen_dnsmasq_fake_items() {
|
||
local fwd_dns=${1}; shift 1
|
||
local outf=${1}; shift 1
|
||
|
||
awk -v fwd_dns="${fwd_dns}" -v outf="${outf}" '
|
||
BEGIN {
|
||
if(outf == "") outf="/dev/stdout";
|
||
split(fwd_dns, dns, ","); setdns=length(dns)>0;
|
||
if(setdns) for(i in dns) if(length(dns[i])==0) delete dns[i];
|
||
fail=1;
|
||
}
|
||
! /^$/&&!/^#/ {
|
||
fail=0
|
||
if(! setdns) {printf("address=%s\n", $0) >>outf; next;}
|
||
if(setdns) for(i in dns) printf("address=/.%s/%s\n", $0, dns[i]) >>outf;
|
||
}
|
||
END {fflush(outf); close(outf); exit(fail);}
|
||
'
|
||
}
|
||
|
||
check_port_exists() {
|
||
port=$1
|
||
protocol=$2
|
||
result=
|
||
if [ "$protocol" = "tcp" ]; then
|
||
result=$(netstat -tln | grep -c ":$port ")
|
||
elif [ "$protocol" = "udp" ]; then
|
||
result=$(netstat -uln | grep -c ":$port ")
|
||
fi
|
||
echo "${result}"
|
||
}
|
||
|
||
get_new_port() {
|
||
port=$1
|
||
[ "$port" == "auto" ] && port=2082
|
||
protocol=$(echo $2 | tr 'A-Z' 'a-z')
|
||
result=$(check_port_exists $port $protocol)
|
||
if [ "$result" != 0 ]; then
|
||
temp=
|
||
if [ "$port" -lt 65535 ]; then
|
||
temp=$(expr $port + 1)
|
||
elif [ "$port" -gt 1 ]; then
|
||
temp=$(expr $port - 1)
|
||
fi
|
||
get_new_port $temp $protocol
|
||
else
|
||
echo $port
|
||
fi
|
||
}
|
||
|
||
first_type() {
|
||
local path_name=${1}
|
||
type -t -p "/bin/${path_name}" -p "${TMP_BIN_PATH}/${path_name}" -p "${path_name}" "$@" | head -n1
|
||
}
|
||
|
||
ln_start_bin() {
|
||
local file_func=${1}
|
||
local ln_name=${2}
|
||
local output=${3}
|
||
|
||
shift 3;
|
||
if [ "${file_func%%/*}" != "${file_func}" ]; then
|
||
[ ! -L "${file_func}" ] && {
|
||
ln -s "${file_func}" "${TMP_BIN_PATH}/${ln_name}" >/dev/null 2>&1
|
||
file_func="${TMP_BIN_PATH}/${ln_name}"
|
||
}
|
||
[ -x "${file_func}" ] || echolog " - $(readlink ${file_func}) 没有执行权限,无法启动:${file_func} $*"
|
||
fi
|
||
#echo "${file_func} $*" >&2
|
||
[ -n "${file_func}" ] || echolog " - 找不到 ${ln_name},无法启动..."
|
||
${file_func:-echolog " - ${ln_name}"} "$@" >${output} 2>&1 &
|
||
}
|
||
|
||
ENABLED=$(config_t_get global enabled 0)
|
||
SOCKS_ENABLED=$(config_t_get global socks_enabled 0)
|
||
|
||
TCP_REDIR_PORT=1041
|
||
TCP_NODE=$(config_t_get global tcp_node nil)
|
||
|
||
UDP_REDIR_PORT=1051
|
||
UDP_NODE=$(config_t_get global udp_node nil)
|
||
|
||
[ "$UDP_NODE" == "tcp_" ] && UDP_NODE=$TCP_NODE
|
||
[ "$UDP_NODE" == "tcp" ] && UDP_REDIR_PORT=$TCP_REDIR_PORT
|
||
|
||
TCP_REDIR_PORTS=$(config_t_get global_forwarding tcp_redir_ports '80,443')
|
||
UDP_REDIR_PORTS=$(config_t_get global_forwarding udp_redir_ports '1:65535')
|
||
TCP_NO_REDIR_PORTS=$(config_t_get global_forwarding tcp_no_redir_ports 'disable')
|
||
UDP_NO_REDIR_PORTS=$(config_t_get global_forwarding udp_no_redir_ports 'disable')
|
||
KCPTUN_REDIR_PORT=$(config_t_get global_forwarding kcptun_port 12948)
|
||
TCP_PROXY_MODE=$(config_t_get global tcp_proxy_mode chnroute)
|
||
UDP_PROXY_MODE=$(config_t_get global udp_proxy_mode chnroute)
|
||
LOCALHOST_TCP_PROXY_MODE=$(config_t_get global localhost_tcp_proxy_mode default)
|
||
LOCALHOST_UDP_PROXY_MODE=$(config_t_get global localhost_udp_proxy_mode default)
|
||
[ "$LOCALHOST_TCP_PROXY_MODE" == "default" ] && LOCALHOST_TCP_PROXY_MODE=$TCP_PROXY_MODE
|
||
[ "$LOCALHOST_UDP_PROXY_MODE" == "default" ] && LOCALHOST_UDP_PROXY_MODE=$UDP_PROXY_MODE
|
||
RESOLVFILE=/tmp/resolv.conf.d/resolv.conf.auto
|
||
[ -f "${RESOLVFILE}" ] && [ -s "${RESOLVFILE}" ] || RESOLVFILE=/tmp/resolv.conf.auto
|
||
|
||
load_config() {
|
||
[ "$ENABLED" != 1 ] && NO_PROXY=1
|
||
[ "$TCP_NODE" == "nil" -a "$UDP_NODE" == "nil" ] && {
|
||
echolog "没有选择节点!"
|
||
NO_PROXY=1
|
||
}
|
||
|
||
count_hosts_str=
|
||
[ -f "${RULES_PATH}/direct_host" ] && direct_hosts_str="$(echo -n $(cat ${RULES_PATH}/direct_host) | sed "s/ /|/g")"
|
||
[ -f "${RULES_PATH}/proxy_host" ] && proxy_hosts_str="$(echo -n $(cat ${RULES_PATH}/proxy_host) | sed "s/ /|/g")"
|
||
[ -n "$direct_hosts_str" ] && {
|
||
tmp="${direct_hosts_str}"
|
||
[ -n "$count_hosts_str" ] && tmp="${count_hosts_str}|${direct_hosts_str}"
|
||
count_hosts_str="$tmp"
|
||
}
|
||
[ -n "$proxy_hosts_str" ] && {
|
||
tmp="${proxy_hosts_str}"
|
||
[ -n "$count_hosts_str" ] && tmp="${count_hosts_str}|${proxy_hosts_str}"
|
||
count_hosts_str="$tmp"
|
||
}
|
||
|
||
global=$(echo "${TCP_PROXY_MODE}${LOCALHOST_TCP_PROXY_MODE}${UDP_PROXY_MODE}${LOCALHOST_UDP_PROXY_MODE}" | grep "global")
|
||
returnhome=$(echo "${TCP_PROXY_MODE}${LOCALHOST_TCP_PROXY_MODE}${UDP_PROXY_MODE}${LOCALHOST_UDP_PROXY_MODE}" | grep "returnhome")
|
||
chnlist=$(echo "${TCP_PROXY_MODE}${LOCALHOST_TCP_PROXY_MODE}${UDP_PROXY_MODE}${LOCALHOST_UDP_PROXY_MODE}" | grep "chnroute")
|
||
gfwlist=$(echo "${TCP_PROXY_MODE}${LOCALHOST_TCP_PROXY_MODE}${UDP_PROXY_MODE}${LOCALHOST_UDP_PROXY_MODE}" | grep "gfwlist")
|
||
DNS_MODE=$(config_t_get global dns_mode pdnsd)
|
||
DNS_FORWARD=$(config_t_get global dns_forward 8.8.4.4:53 | sed 's/:/#/g')
|
||
DNS_CACHE=$(config_t_get global dns_cache 0)
|
||
LOCAL_DNS="default"
|
||
if [ "${LOCAL_DNS}" = "default" ]; then
|
||
DEFAULT_DNS=$(uci show dhcp | grep "@dnsmasq" | grep "\.server=" | awk -F '=' '{print $2}' | sed "s/'//g" | tr ' ' ',')
|
||
if [ -z "${DEFAULT_DNS}" ]; then
|
||
DEFAULT_DNS=$(echo -n $(sed -n 's/^nameserver[ \t]*\([^ ]*\)$/\1/p' "${RESOLVFILE}" | grep -v "0.0.0.0" | grep -v "127.0.0.1" | grep -v "^::$" | head -2) | tr ' ' ',')
|
||
fi
|
||
LOCAL_DNS="${DEFAULT_DNS:-119.29.29.29}"
|
||
IS_DEFAULT_DNS=1
|
||
fi
|
||
PROXY_IPV6=$(config_t_get global_forwarding proxy_ipv6 0)
|
||
export XRAY_LOCATION_ASSET=$(config_t_get global_rules xray_location_asset "/usr/share/xray/")
|
||
mkdir -p /var/etc $TMP_PATH $TMP_BIN_PATH $TMP_ID_PATH $TMP_PORT_PATH $TMP_ROUTE_PATH
|
||
return 0
|
||
}
|
||
|
||
run_socks() {
|
||
local flag=$1
|
||
local node=$2
|
||
local bind=$3
|
||
local socks_port=$4
|
||
local config_file=$5
|
||
local http_port=$6
|
||
local http_config_file=$7
|
||
local relay_port=$8
|
||
local log_file="/dev/null"
|
||
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
|
||
local remarks=$(config_n_get $node remarks)
|
||
local server_host=$(config_n_get $node address)
|
||
local port=$(config_n_get $node port)
|
||
[ -n "$relay_port" ] && {
|
||
server_host="127.0.0.1"
|
||
port=$relay_port
|
||
}
|
||
local msg tmp
|
||
|
||
if [ -n "$server_host" ] && [ -n "$port" ]; then
|
||
server_host=$(host_from_url "$server_host")
|
||
[ -n "$(echo -n $server_host | awk '{print gensub(/[!-~]/,"","g",$0)}')" ] && msg="$remarks,非法的代理服务器地址,无法启动 !"
|
||
tmp="(${server_host}:${port})"
|
||
else
|
||
msg="某种原因,此 Socks 服务的相关配置已失联,启动中止!"
|
||
fi
|
||
|
||
if [ "$type" == "xray" ] && ([ -n "$(config_n_get $node balancing_node)" ] || [ "$(config_n_get $node default_node)" != "_direct" -a "$(config_n_get $node default_node)" != "_blackhole" ]); then
|
||
unset msg
|
||
fi
|
||
|
||
[ -n "${msg}" ] && {
|
||
[ "$bind" != "127.0.0.1" ] && echolog " - 启动中止 ${bind}:${socks_port} ${msg}"
|
||
return 1
|
||
}
|
||
[ "$bind" != "127.0.0.1" ] && echolog " - 启动 ${bind}:${socks_port} - 节点:$remarks${tmp}"
|
||
|
||
case "$type" in
|
||
socks|\
|
||
xray)
|
||
[ "$http_port" != "0" ] && {
|
||
local extra_param="-http_proxy_port $http_port"
|
||
config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g")
|
||
}
|
||
lua $API_GEN_XRAY -node $node -socks_proxy_port $socks_port $extra_param > $config_file
|
||
ln_start_bin "$(first_type $(config_t_get global_app xray_file) xray)" xray $log_file -config="$config_file"
|
||
;;
|
||
trojan-go)
|
||
lua $API_GEN_TROJAN -node $node -run_type client -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $port > $config_file
|
||
ln_start_bin "$(first_type $(config_t_get global_app trojan_go_file) trojan-go)" trojan-go $log_file -config "$config_file"
|
||
;;
|
||
trojan*)
|
||
lua $API_GEN_TROJAN -node $node -run_type client -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $port > $config_file
|
||
ln_start_bin "$(first_type ${type})" "${type}" $log_file -c "$config_file"
|
||
;;
|
||
naiveproxy)
|
||
lua $API_GEN_NAIVE -node $node -run_type socks -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $port > $config_file
|
||
ln_start_bin "$(first_type naive)" naive $log_file "$config_file"
|
||
;;
|
||
brook)
|
||
local protocol=$(config_n_get $node protocol client)
|
||
local brook_tls=$(config_n_get $node brook_tls 0)
|
||
[ "$protocol" == "wsclient" ] && {
|
||
[ "$brook_tls" == "1" ] && server_host="wss://${server_host}" || server_host="ws://${server_host}"
|
||
}
|
||
ln_start_bin "$(first_type $(config_t_get global_app brook_file) brook)" "brook_SOCKS_${flag}" $log_file "$protocol" --socks5 "$bind:$socks_port" -s "$server_host:$port" -p "$(config_n_get $node password)"
|
||
;;
|
||
ss|ssr)
|
||
lua $API_GEN_SS -node $node -local_addr "0.0.0.0" -local_port $socks_port -server_host $server_host -server_port $port > $config_file
|
||
ss_program="$(first_type ${type}local ${type}-local)"
|
||
[ "$(printf '%s' "$ss_program" | awk -F '/' '{print $NF}')" = "${type}local" ] && \
|
||
ss_extra_arg="-U" || ss_extra_arg="-u"
|
||
ln_start_bin "$ss_program" "${type}-local" $log_file -c "$config_file" -v $ss_extra_arg
|
||
;;
|
||
esac
|
||
|
||
# http to socks
|
||
[ "$type" != "xray" ] && [ "$type" != "socks" ] && [ "$http_port" != "0" ] && [ "$http_config_file" != "nil" ] && {
|
||
lua $API_GEN_XRAY_PROTO -local_proto http -local_address "0.0.0.0" -local_port $http_port -server_proto socks -server_address "127.0.0.1" -server_port $socks_port -server_username $_username -server_password $_password > $http_config_file
|
||
echo lua $API_GEN_XRAY_PROTO -local_proto http -local_address "0.0.0.0" -local_port $http_port -server_proto socks -server_address "127.0.0.1" -server_port $socks_port -server_username $_username -server_password $_password
|
||
ln_start_bin "$(first_type $(config_t_get global_app xray_file) xray)" xray $log_file -config="$http_config_file"
|
||
}
|
||
}
|
||
|
||
run_redir() {
|
||
local node=$1
|
||
local bind=$2
|
||
local local_port=$3
|
||
local config_file=$4
|
||
local REDIR_TYPE=$5
|
||
local log_file=$6
|
||
[ -z "$log_file" ] && log_file="/dev/null"
|
||
local redir_type=$(echo $REDIR_TYPE | tr 'A-Z' 'a-z')
|
||
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
|
||
local close_log=$(config_t_get global close_log_${redir_type} 1)
|
||
[ "$close_log" = "1" ] && log_file="/dev/null"
|
||
local remarks=$(config_n_get $node remarks)
|
||
local server_host=$(config_n_get $node address)
|
||
local port=$(config_n_get $node port)
|
||
[ -n "$server_host" -a -n "$port" ] && {
|
||
# 判断节点服务器地址是否URL并去掉~
|
||
local server_host=$(host_from_url "$server_host")
|
||
# 判断节点服务器地址是否包含汉字~
|
||
local tmp=$(echo -n $server_host | awk '{print gensub(/[!-~]/,"","g",$0)}')
|
||
[ -n "$tmp" ] && {
|
||
echolog "$remarks节点,非法的服务器地址,无法启动!"
|
||
return 1
|
||
}
|
||
[ "$bind" != "127.0.0.1" ] && echolog "${REDIR_TYPE}节点:$remarks,节点:${server_host}:${port},监听端口:$local_port"
|
||
}
|
||
eval ${REDIR_TYPE}_NODE_PORT=$port
|
||
|
||
case "$REDIR_TYPE" in
|
||
UDP)
|
||
case "$type" in
|
||
socks)
|
||
local node_address=$(config_n_get $node address)
|
||
local node_port=$(config_n_get $node port)
|
||
local server_username=$(config_n_get $node username)
|
||
local server_password=$(config_n_get $node password)
|
||
eval port=\$UDP_REDIR_PORT
|
||
ln_start_bin "$(first_type ipt2socks)" "ipt2socks_udp" $log_file -U -l "$port" -b 0.0.0.0 -s "$node_address" -p "$node_port" -R -v
|
||
;;
|
||
xray)
|
||
local loglevel=$(config_t_get global loglevel "warning")
|
||
lua $API_GEN_XRAY -node $node -proto udp -redir_port $local_port -loglevel $loglevel > $config_file
|
||
ln_start_bin "$(first_type $(config_t_get global_app xray_file) xray)" xray $log_file -config="$config_file"
|
||
;;
|
||
trojan-go)
|
||
local loglevel=$(config_t_get global trojan_loglevel "2")
|
||
lua $API_GEN_TROJAN -node $node -run_type nat -local_addr "0.0.0.0" -local_port $local_port -loglevel $loglevel > $config_file
|
||
ln_start_bin "$(first_type $(config_t_get global_app trojan_go_file) trojan-go)" trojan-go $log_file -config "$config_file"
|
||
;;
|
||
trojan*)
|
||
local loglevel=$(config_t_get global trojan_loglevel "2")
|
||
lua $API_GEN_TROJAN -node $node -run_type nat -local_addr "0.0.0.0" -local_port $local_port -loglevel $loglevel > $config_file
|
||
ln_start_bin "$(first_type ${type})" "${type}" $log_file -c "$config_file"
|
||
;;
|
||
naiveproxy)
|
||
echolog "Naiveproxy不支持UDP转发!"
|
||
;;
|
||
brook)
|
||
local protocol=$(config_n_get $node protocol client)
|
||
if [ "$protocol" == "wsclient" ]; then
|
||
echolog "Brook的WebSocket不支持UDP转发!"
|
||
else
|
||
ln_start_bin "$(first_type $(config_t_get global_app brook_file) brook)" "brook_udp" $log_file tproxy -l ":$local_port" -s "$server_host:$port" -p "$(config_n_get $node password)"
|
||
fi
|
||
;;
|
||
ss|ssr)
|
||
lua $API_GEN_SS -node $node -local_addr "0.0.0.0" -local_port $local_port > $config_file
|
||
ss_program="$(first_type ${type}local ${type}-redir)"
|
||
[ "$(printf '%s' "$ss_program" | awk -F '/' '{print $NF}')" = "${type}local" ] && \
|
||
ss_extra_arg="--protocol redir -u" || ss_extra_arg="-U"
|
||
ln_start_bin "$ss_program" "${type}-redir" $log_file -c "$config_file" -v $ss_extra_arg
|
||
;;
|
||
esac
|
||
;;
|
||
TCP)
|
||
local kcptun_use=$(config_n_get $node use_kcp 0)
|
||
if [ "$kcptun_use" == "1" ]; then
|
||
local kcptun_server_host=$(config_n_get $node kcp_server)
|
||
local network_type="ipv4"
|
||
local kcptun_port=$(config_n_get $node kcp_port)
|
||
local kcptun_config="$(config_n_get $node kcp_opts)"
|
||
if [ -z "$kcptun_port" -o -z "$kcptun_config" ]; then
|
||
echolog "Kcptun未配置参数,错误!"
|
||
return 1
|
||
fi
|
||
if [ -n "$kcptun_port" -a -n "$kcptun_config" ]; then
|
||
local run_kcptun_ip=$server_host
|
||
[ -n "$kcptun_server_host" ] && run_kcptun_ip=$(get_host_ip $network_type $kcptun_server_host)
|
||
KCPTUN_REDIR_PORT=$(get_new_port $KCPTUN_REDIR_PORT tcp)
|
||
kcptun_params="-l 0.0.0.0:$KCPTUN_REDIR_PORT -r $run_kcptun_ip:$kcptun_port $kcptun_config"
|
||
ln_start_bin "$(first_type $(config_t_get global_app kcptun_client_file) kcptun-client)" "kcptun_tcp" $log_file $kcptun_params
|
||
fi
|
||
fi
|
||
local _socks_flag _socks_address _socks_port _socks_username _socks_password
|
||
case "$type" in
|
||
socks)
|
||
_socks_flag=1
|
||
_socks_address=$(config_n_get $node address)
|
||
_socks_port=$(config_n_get $node port)
|
||
_socks_username=$(config_n_get $node username)
|
||
_socks_password=$(config_n_get $node password)
|
||
;;
|
||
xray)
|
||
local loglevel=$(config_t_get global loglevel "warning")
|
||
local proto="-proto tcp"
|
||
[ "$UDP_NODE" == "tcp" ] && proto="-proto tcp,udp"
|
||
local extra_param="${proto}"
|
||
[ "$tcp_node_socks" = "1" ] && {
|
||
local socks_param="-socks_proxy_port $tcp_node_socks_port"
|
||
extra_param="${extra_param} ${socks_param}"
|
||
config_file=$(echo $config_file | sed "s/TCP/TCP_SOCKS_$tcp_node_socks_id/g")
|
||
}
|
||
[ "$tcp_node_http" = "1" ] && {
|
||
local http_param="-http_proxy_port $tcp_node_http_port"
|
||
extra_param="${extra_param} ${http_param}"
|
||
config_file=$(echo $config_file | sed "s/TCP/TCP_HTTP_$tcp_node_http_id/g")
|
||
}
|
||
lua $API_GEN_XRAY -node $node -redir_port $local_port -loglevel $loglevel $extra_param > $config_file
|
||
ln_start_bin "$(first_type $(config_t_get global_app xray_file) xray)" xray $log_file -config="$config_file"
|
||
;;
|
||
trojan-go)
|
||
local loglevel=$(config_t_get global trojan_loglevel "2")
|
||
lua $API_GEN_TROJAN -node $node -run_type nat -local_addr "0.0.0.0" -local_port $local_port -loglevel $loglevel > $config_file
|
||
ln_start_bin "$(first_type $(config_t_get global_app trojan_go_file) trojan-go)" trojan-go $log_file -config "$config_file"
|
||
;;
|
||
trojan*)
|
||
local loglevel=$(config_t_get global trojan_loglevel "2")
|
||
lua $API_GEN_TROJAN -node $node -run_type nat -local_addr "0.0.0.0" -local_port $local_port -loglevel $loglevel > $config_file
|
||
ln_start_bin "$(first_type ${type})" "${type}" $log_file -c "$config_file"
|
||
;;
|
||
naiveproxy)
|
||
lua $API_GEN_NAIVE -node $node -run_type redir -local_addr "0.0.0.0" -local_port $local_port > $config_file
|
||
ln_start_bin "$(first_type naive)" naive $log_file "$config_file"
|
||
;;
|
||
brook)
|
||
local server_ip=$server_host
|
||
local protocol=$(config_n_get $node protocol client)
|
||
local brook_tls=$(config_n_get $node brook_tls 0)
|
||
if [ "$protocol" == "wsclient" ]; then
|
||
[ "$brook_tls" == "1" ] && server_ip="wss://${server_ip}" || server_ip="ws://${server_ip}"
|
||
socks_port=$(get_new_port 2081 tcp)
|
||
ln_start_bin "$(first_type $(config_t_get global_app brook_file) brook)" "brook_tcp" $log_file wsclient --socks5 "127.0.0.1:$socks_port" -s "$server_ip:$port" -p "$(config_n_get $node password)"
|
||
_socks_flag=1
|
||
_socks_address="127.0.0.1"
|
||
_socks_port=$socks_port
|
||
echolog "Brook的WebSocket不支持透明代理,将使用ipt2socks转换透明代理!"
|
||
[ "$UDP_NODE" == "tcp" ] && echolog "Brook的WebSocket不支持UDP转发!"
|
||
else
|
||
[ "$kcptun_use" == "1" ] && {
|
||
server_ip=127.0.0.1
|
||
port=$KCPTUN_REDIR_PORT
|
||
}
|
||
ln_start_bin "$(first_type $(config_t_get global_app brook_file) brook)" "brook_tcp" $log_file tproxy -l ":$local_port" -s "$server_ip:$port" -p "$(config_n_get $node password)"
|
||
fi
|
||
;;
|
||
ss|ssr)
|
||
ss_program="$(first_type ${type}local ${type}-redir)"
|
||
[ "$(printf '%s' "$ss_program" | awk -F '/' '{print $NF}')" = "${type}local" ] && \
|
||
ss_extra_arg="--protocol redir"
|
||
if [ "$kcptun_use" == "1" ]; then
|
||
lua $API_GEN_SS -node $node -local_addr "0.0.0.0" -local_port $local_port -server_host "127.0.0.1" -server_port $KCPTUN_REDIR_PORT > $config_file
|
||
[ "$UDP_NODE" == "tcp" ] && echolog "Kcptun不支持UDP转发!"
|
||
else
|
||
lua $API_GEN_SS -node $node -local_addr "0.0.0.0" -local_port $local_port > $config_file
|
||
[ "$UDP_NODE" == "tcp" ] && ss_extra_arg="$ss_extra_arg -u"
|
||
fi
|
||
ln_start_bin "$ss_program" "${type}-redir" $log_file -c "$config_file" -v $ss_extra_arg
|
||
;;
|
||
esac
|
||
if [ -n "$_socks_flag" ]; then
|
||
local extra_param="-T"
|
||
[ "$UDP_NODE" == "tcp" ] && extra_param=""
|
||
ln_start_bin "$(first_type ipt2socks)" "ipt2socks_tcp" $log_file -l "$local_port" -b 0.0.0.0 -s "$_socks_address" -p "$_socks_port" -R -v $extra_param
|
||
fi
|
||
unset _socks_flag _socks_address _socks_port _socks_username _socks_password
|
||
|
||
[ "$type" != "xray" ] && {
|
||
[ "$tcp_node_socks" = "1" ] && {
|
||
local port=$tcp_node_socks_port
|
||
local config_file=$TMP_PATH/SOCKS_$tcp_node_socks_id.json
|
||
local log_file=$TMP_PATH/SOCKS_$tcp_node_socks_id.log
|
||
local http_port=0
|
||
local http_config_file=$TMP_PATH/HTTP2SOCKS_$tcp_node_http_id.json
|
||
[ "$tcp_node_http" = "1" ] && {
|
||
http_port=$tcp_node_http_port
|
||
}
|
||
run_socks TCP $node "0.0.0.0" $port $config_file $http_port $http_config_file
|
||
}
|
||
}
|
||
;;
|
||
esac
|
||
return 0
|
||
}
|
||
|
||
node_switch() {
|
||
[ -n "$1" -a -n "$2" ] && {
|
||
local node=$2
|
||
top -bn1 | grep -E "$TMP_PATH" | grep -i "${1}" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||
local config_file=$TMP_PATH/${1}.json
|
||
local log_file=$TMP_PATH/${1}.log
|
||
eval current_port=\$${1}_REDIR_PORT
|
||
local port=$(cat $TMP_PORT_PATH/${1})
|
||
|
||
local ids=$(uci show $CONFIG | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
||
for id in $ids; do
|
||
[ "$(config_n_get $id enabled 0)" == "0" ] && continue
|
||
[ "$(config_n_get $id node nil)" != "tcp" ] && continue
|
||
local socks_port=$(config_n_get $id port)
|
||
local http_port=$(config_n_get $id http_port 0)
|
||
top -bn1 | grep -E "$TMP_PATH" | grep -i "SOCKS" | grep "$id" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||
tcp_node_socks=1
|
||
tcp_node_socks_port=$socks_port
|
||
tcp_node_socks_id=$id
|
||
[ "$http_port" != "0" ] && {
|
||
tcp_node_http=1
|
||
tcp_node_http_port=$http_port
|
||
tcp_node_http_id=$id
|
||
}
|
||
break
|
||
done
|
||
|
||
run_redir $node "0.0.0.0" $port $config_file $1 $log_file
|
||
echo $node > $TMP_ID_PATH/${1}
|
||
|
||
[ "$1" = "TCP" ] && {
|
||
[ "$(config_t_get global udp_node nil)" = "tcp_" ] && {
|
||
top -bn1 | grep -E "$TMP_PATH" | grep -i "UDP" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||
UDP_NODE=$node
|
||
start_redir UDP
|
||
}
|
||
}
|
||
|
||
#local node_net=$(echo $1 | tr 'A-Z' 'a-z')
|
||
#uci set $CONFIG.@global[0].${node_net}_node=$node
|
||
#uci commit $CONFIG
|
||
restart_dnsmasq
|
||
}
|
||
}
|
||
|
||
start_redir() {
|
||
eval node=\$${1}_NODE
|
||
[ "$node" != "nil" ] && {
|
||
TYPE=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
|
||
local config_file=$TMP_PATH/${1}.json
|
||
local log_file=$TMP_PATH/${1}.log
|
||
eval current_port=\$${1}_REDIR_PORT
|
||
local port=$(echo $(get_new_port $current_port $1))
|
||
eval ${1}_REDIR=$port
|
||
run_redir $node "0.0.0.0" $port $config_file $1 $log_file
|
||
#eval ip=\$${1}_NODE_IP
|
||
echo $node > $TMP_ID_PATH/${1}
|
||
echo $port > $TMP_PORT_PATH/${1}
|
||
}
|
||
}
|
||
|
||
start_socks() {
|
||
local ids=$(uci show $CONFIG | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
||
echolog "分析 Socks 服务的节点配置..."
|
||
for id in $ids; do
|
||
local enabled=$(config_n_get $id enabled 0)
|
||
[ "$enabled" == "0" ] && continue
|
||
local node=$(config_n_get $id node nil)
|
||
[ "$node" == "nil" ] && continue
|
||
local port=$(config_n_get $id port)
|
||
local config_file=$TMP_PATH/SOCKS_${id}.json
|
||
local log_file=$TMP_PATH/SOCKS_${id}.log
|
||
local http_port=$(config_n_get $id http_port 0)
|
||
local http_config_file=$TMP_PATH/HTTP2SOCKS_${id}.json
|
||
[ "$node" == "tcp" ] && {
|
||
tcp_node_socks=1
|
||
tcp_node_socks_port=$port
|
||
tcp_node_socks_id=$id
|
||
[ "$http_port" != "0" ] && {
|
||
tcp_node_http=1
|
||
tcp_node_http_port=$http_port
|
||
tcp_node_http_id=$id
|
||
}
|
||
continue
|
||
}
|
||
run_socks $id $node "0.0.0.0" $port $config_file $http_port $http_config_file
|
||
done
|
||
}
|
||
|
||
clean_log() {
|
||
logsnum=$(cat $LOG_FILE 2>/dev/null | wc -l)
|
||
[ "$logsnum" -gt 1000 ] && {
|
||
echo "" > $LOG_FILE
|
||
echolog "日志文件过长,清空处理!"
|
||
}
|
||
}
|
||
|
||
clean_crontab() {
|
||
touch /etc/crontabs/root
|
||
#sed -i "/${CONFIG}/d" /etc/crontabs/root >/dev/null 2>&1
|
||
sed -i "/$(echo "/etc/init.d/${CONFIG}" | sed 's#\/#\\\/#g')/d" /etc/crontabs/root >/dev/null 2>&1
|
||
sed -i "/$(echo "lua ${APP_PATH}/rule_update.lua log" | sed 's#\/#\\\/#g')/d" /etc/crontabs/root >/dev/null 2>&1
|
||
sed -i "/$(echo "lua ${APP_PATH}/subscribe.lua start log" | sed 's#\/#\\\/#g')/d" /etc/crontabs/root >/dev/null 2>&1
|
||
}
|
||
|
||
start_crontab() {
|
||
clean_crontab
|
||
auto_on=$(config_t_get global_delay auto_on 0)
|
||
if [ "$auto_on" = "1" ]; then
|
||
time_off=$(config_t_get global_delay time_off)
|
||
time_on=$(config_t_get global_delay time_on)
|
||
time_restart=$(config_t_get global_delay time_restart)
|
||
[ -z "$time_off" -o "$time_off" != "nil" ] && {
|
||
echo "0 $time_off * * * /etc/init.d/$CONFIG stop" >>/etc/crontabs/root
|
||
echolog "配置定时任务:每天 $time_off 点关闭服务。"
|
||
}
|
||
[ -z "$time_on" -o "$time_on" != "nil" ] && {
|
||
echo "0 $time_on * * * /etc/init.d/$CONFIG start" >>/etc/crontabs/root
|
||
echolog "配置定时任务:每天 $time_on 点开启服务。"
|
||
}
|
||
[ -z "$time_restart" -o "$time_restart" != "nil" ] && {
|
||
echo "0 $time_restart * * * /etc/init.d/$CONFIG restart" >>/etc/crontabs/root
|
||
echolog "配置定时任务:每天 $time_restart 点重启服务。"
|
||
}
|
||
fi
|
||
[ "$NO_PROXY" == 1 ] && {
|
||
echolog "运行于非代理模式,仅允许服务启停的定时任务。"
|
||
/etc/init.d/cron restart
|
||
return
|
||
}
|
||
|
||
autoupdate=$(config_t_get global_rules auto_update)
|
||
weekupdate=$(config_t_get global_rules week_update)
|
||
dayupdate=$(config_t_get global_rules time_update)
|
||
if [ "$autoupdate" = "1" ]; then
|
||
local t="0 $dayupdate * * $weekupdate"
|
||
[ "$weekupdate" = "7" ] && t="0 $dayupdate * * *"
|
||
echo "$t lua $APP_PATH/rule_update.lua log > /dev/null 2>&1 &" >>/etc/crontabs/root
|
||
echolog "配置定时任务:自动更新规则。"
|
||
fi
|
||
|
||
autoupdatesubscribe=$(config_t_get global_subscribe auto_update_subscribe)
|
||
weekupdatesubscribe=$(config_t_get global_subscribe week_update_subscribe)
|
||
dayupdatesubscribe=$(config_t_get global_subscribe time_update_subscribe)
|
||
if [ "$autoupdatesubscribe" = "1" ]; then
|
||
local t="0 $dayupdatesubscribe * * $weekupdatesubscribe"
|
||
[ "$weekupdatesubscribe" = "7" ] && t="0 $dayupdatesubscribe * * *"
|
||
echo "$t lua $APP_PATH/subscribe.lua start log > /dev/null 2>&1 &" >>/etc/crontabs/root
|
||
echolog "配置定时任务:自动更新节点订阅。"
|
||
fi
|
||
|
||
start_daemon=$(config_t_get global_delay start_daemon 0)
|
||
[ "$start_daemon" = "1" ] && $APP_PATH/monitor.sh > /dev/null 2>&1 &
|
||
|
||
AUTO_SWITCH_ENABLE=$(config_t_get auto_switch enable 0)
|
||
[ "$AUTO_SWITCH_ENABLE" = "1" ] && $APP_PATH/test.sh > /dev/null 2>&1 &
|
||
|
||
/etc/init.d/cron restart
|
||
}
|
||
|
||
stop_crontab() {
|
||
clean_crontab
|
||
/etc/init.d/cron restart
|
||
#echolog "清除定时执行命令。"
|
||
}
|
||
|
||
start_dns() {
|
||
local pdnsd_forward other_port msg
|
||
dns_listen_port=${DNS_PORT}
|
||
pdnsd_forward=${DNS_FORWARD}
|
||
|
||
china_ng_listen_port=$(expr $dns_listen_port + 1)
|
||
china_ng_listen="127.0.0.1#${china_ng_listen_port}"
|
||
china_ng_chn=$(echo -n $(echo "${LOCAL_DNS}" | sed "s/,/\n/g" | head -n2) | tr " " ",")
|
||
china_ng_gfw="127.0.0.1#${dns_listen_port}"
|
||
[ -n "${returnhome}" ] && china_ng_chn="${china_ng_gfw}" && china_ng_gfw="${LOCAL_DNS}"
|
||
|
||
echolog "过滤服务配置:准备接管域名解析..."
|
||
|
||
case "$DNS_MODE" in
|
||
nonuse)
|
||
echolog " - 不过滤DNS..."
|
||
TUN_DNS=""
|
||
use_chinadns_ng=$(config_t_get global always_use_chinadns_ng 0)
|
||
[ "$use_chinadns_ng" == "0" ] && return
|
||
;;
|
||
dns2socks)
|
||
local dns2socks_socks_server=$(echo $(config_t_get global socks_server 127.0.0.1:9050) | sed "s/#/:/g")
|
||
local dns2socks_forward=$(get_first_dns DNS_FORWARD 53 | sed 's/#/:/g')
|
||
[ "$DNS_CACHE" == "0" ] && local dns2sock_cache="/d"
|
||
ln_start_bin "$(first_type dns2socks)" dns2socks "/dev/null" "$dns2socks_socks_server" "$dns2socks_forward" "127.0.0.1:$dns_listen_port" $dns2sock_cache
|
||
echolog " - dns2sock(127.0.0.1:${dns_listen_port}${dns2sock_cache}),${dns2socks_socks_server:-127.0.0.1:9050} -> ${dns2socks_forward-D8.8.8.8:53}"
|
||
echolog " - 域名解析:dns2socks..."
|
||
;;
|
||
xray_doh)
|
||
up_trust_doh_dns=$(config_t_get global up_trust_doh_dns "tcp")
|
||
if [ "$up_trust_doh_dns" = "socks" ]; then
|
||
use_tcp_node_resolve_dns=0
|
||
msg="Socks节点"
|
||
elif [ "${up_trust_doh_dns}" = "tcp" ]; then
|
||
use_tcp_node_resolve_dns=1
|
||
msg="TCP节点"
|
||
fi
|
||
up_trust_doh=$(config_t_get global up_trust_doh "https://dns.google/dns-query,8.8.4.4")
|
||
_doh_url=$(echo $up_trust_doh | awk -F ',' '{print $1}')
|
||
_doh_host_port=$(echo $_doh_url | sed "s/https:\/\///g" | awk -F '/' '{print $1}')
|
||
_doh_host=$(echo $_doh_host_port | awk -F ':' '{print $1}')
|
||
_doh_port=$(echo $_doh_host_port | awk -F ':' '{print $2}')
|
||
_doh_bootstrap=$(echo $up_trust_doh | cut -d ',' -sf 2-)
|
||
|
||
up_trust_doh_dns=$(config_t_get global up_trust_doh_dns "tcp")
|
||
if [ "$up_trust_doh_dns" = "socks" ]; then
|
||
socks_server=$(echo $(config_t_get global socks_server 127.0.0.1:9050) | sed "s/#/:/g")
|
||
socks_address=$(echo $socks_server | awk -F ':' '{print $1}')
|
||
socks_port=$(echo $socks_server | awk -F ':' '{print $2}')
|
||
lua $API_GEN_XRAY -dns_listen_port "${dns_listen_port}" -dns_server "${_doh_bootstrap}" -doh_url "${_doh_url}" -doh_host "${_doh_host}" -doh_socks_address "${socks_address}" -doh_socks_port "${socks_port}" > $TMP_PATH/DNS.json
|
||
ln_start_bin "$(first_type $(config_t_get global_app xray_file) xray)" xray $TMP_PATH/DNS.log -config="$TMP_PATH/DNS.json"
|
||
elif [ "${up_trust_doh_dns}" = "tcp" ]; then
|
||
DNS_FORWARD=""
|
||
_doh_bootstrap_dns=$(echo $_doh_bootstrap | sed "s/,/ /g")
|
||
for _dns in $_doh_bootstrap_dns; do
|
||
_dns=$(echo $_dns | awk -F ':' '{print $1}'):${_doh_port:-443}
|
||
[ -n "$DNS_FORWARD" ] && DNS_FORWARD=${DNS_FORWARD},${_dns} || DNS_FORWARD=${_dns}
|
||
done
|
||
lua $API_GEN_XRAY -dns_listen_port "${dns_listen_port}" -dns_server "${_doh_bootstrap}" -doh_url "${_doh_url}" -doh_host "${_doh_host}" > $TMP_PATH/DNS.json
|
||
ln_start_bin "$(first_type $(config_t_get global_app xray_file) xray)" xray $TMP_PATH/DNS.log -config="$TMP_PATH/DNS.json"
|
||
unset _dns _doh_bootstrap_dns
|
||
fi
|
||
unset _doh_url _doh_port _doh_bootstrap
|
||
echolog " - 域名解析 Xray DNS(DoH)..."
|
||
;;
|
||
pdnsd)
|
||
gen_pdnsd_config "${dns_listen_port}" "${pdnsd_forward}"
|
||
ln_start_bin "$(first_type pdnsd)" pdnsd "/dev/null" --daemon -c "${TMP_PATH}/pdnsd/pdnsd.conf" -d
|
||
echolog " - 域名解析:pdnsd + 使用(TCP节点)解析域名..."
|
||
;;
|
||
udp)
|
||
use_udp_node_resolve_dns=1
|
||
TUN_DNS=${DNS_FORWARD}
|
||
echolog " - 域名解析:直接使用UDP节点请求DNS($TUN_DNS)"
|
||
;;
|
||
fake_ip)
|
||
TUN_DNS="11.1.1.1"
|
||
echolog " - 域名解析:使用FakeIP方案..."
|
||
;;
|
||
custom)
|
||
custom_dns=$(config_t_get global custom_dns)
|
||
TUN_DNS="$(echo ${custom_dns} | sed 's/:/#/g')"
|
||
echolog " - 域名解析:使用UDP协议自定义DNS($TUN_DNS)解析..."
|
||
;;
|
||
esac
|
||
|
||
[ -n "$chnlist" ] && [ "$DNS_MODE" != "custom" ] && [ "$DNS_MODE" != "fake_ip" ] && {
|
||
[ -n "$(first_type chinadns-ng)" ] && {
|
||
echolog "发现ChinaDNS-NG,将启动。"
|
||
CHINADNS_NG=1
|
||
}
|
||
[ -n "$CHINADNS_NG" ] && {
|
||
echolog " | - (chinadns-ng) 只支持2~4级的域名过滤..."
|
||
if [ "$DNS_MODE" = "pdnsd" ]; then
|
||
msg="pdnsd"
|
||
elif [ "$DNS_MODE" = "dns2socks" ]; then
|
||
msg="dns2socks"
|
||
elif [ "$DNS_MODE" = "xray_doh" ]; then
|
||
msg="Xray DNS(DoH)"
|
||
elif [ "$DNS_MODE" = "udp" ]; then
|
||
use_udp_node_resolve_dns=1
|
||
china_ng_gfw="${DNS_FORWARD}"
|
||
msg="udp"
|
||
elif [ "$DNS_MODE" = "custom" ]; then
|
||
custom_dns=$(config_t_get global custom_dns)
|
||
china_ng_gfw="$(echo ${custom_dns} | sed 's/:/#/g')"
|
||
msg="自定义DNS"
|
||
fi
|
||
|
||
local gfwlist_param="${TMP_PATH}/chinadns_gfwlist"
|
||
[ -f "${RULES_PATH}/gfwlist" ] && cp -a "${RULES_PATH}/gfwlist" "${gfwlist_param}"
|
||
local chnlist_param="${TMP_PATH}/chinadns_chnlist"
|
||
[ -f "${RULES_PATH}/chnlist" ] && cp -a "${RULES_PATH}/chnlist" "${chnlist_param}"
|
||
|
||
[ -f "${RULES_PATH}/proxy_host" ] && {
|
||
cat "${RULES_PATH}/proxy_host" >> "${gfwlist_param}"
|
||
echolog " | - [$?](chinadns-ng) 代理域名表合并到防火墙域名表"
|
||
}
|
||
[ -f "${RULES_PATH}/direct_host" ] && {
|
||
cat "${RULES_PATH}/direct_host" >> "${chnlist_param}"
|
||
echolog " | - [$?](chinadns-ng) 域名白名单合并到中国域名表"
|
||
}
|
||
chnlist_param=${chnlist_param:+-m "${chnlist_param}" -M}
|
||
ln_start_bin "$(first_type chinadns-ng)" chinadns-ng "${TMP_PATH}/chinadns-ng.log" -v -b 0.0.0.0 -l "${china_ng_listen_port}" ${china_ng_chn:+-c "${china_ng_chn}"} ${chnlist_param} ${china_ng_gfw:+-t "${china_ng_gfw}"} ${gfwlist_param:+-g "${gfwlist_param}"} -f
|
||
echolog " + 过滤服务:ChinaDNS-NG(:${china_ng_listen_port}) + ${msg}:国内DNS:${china_ng_chn:-D114.114.114.114},可信DNS:${china_ng_gfw:-D8.8.8.8}"
|
||
#[ -n "${global}${chnlist}" ] && [ -z "${returnhome}" ] && TUN_DNS="${china_ng_gfw}"
|
||
}
|
||
}
|
||
|
||
[ "${use_udp_node_resolve_dns}" = "1" ] && echolog " * 要求代理 DNS 请求,如上游 DNS 非直连地址,确保 UDP 代理打开,并且已经正确转发!"
|
||
[ "${use_tcp_node_resolve_dns}" = "1" ] && echolog " * 请确认上游 DNS 支持 TCP 查询,如非直连地址,确保 TCP 代理打开,并且已经正确转发!"
|
||
}
|
||
|
||
add_dnsmasq() {
|
||
local fwd_dns items item servers msg
|
||
|
||
mkdir -p "${TMP_DNSMASQ_PATH}" "${DNSMASQ_PATH}" "/var/dnsmasq.d"
|
||
[ "$(config_t_get global_rules adblock 0)" = "1" ] && {
|
||
ln -s "${RULES_PATH}/adblock.conf" "${TMP_DNSMASQ_PATH}/adblock.conf"
|
||
echolog " - [$?]广告域名表中域名解析请求直接应答为 '0.0.0.0'"
|
||
}
|
||
|
||
if [ "${DNS_MODE}" = "nonuse" ]; then
|
||
echolog " - 不对域名进行分流解析"
|
||
else
|
||
#屏蔽列表
|
||
sort -u "${RULES_PATH}/block_host" | gen_dnsmasq_fake_items "0.0.0.0" "${TMP_DNSMASQ_PATH}/00-block_host.conf"
|
||
|
||
#始终用国内DNS解析节点域名
|
||
fwd_dns="${LOCAL_DNS}"
|
||
servers=$(uci show "${CONFIG}" | grep ".address=" | cut -d "'" -f 2)
|
||
hosts_foreach "servers" host_from_url | grep -v "google.c" | grep '[a-zA-Z]$' | sort -u | gen_dnsmasq_items "vpsiplist,vpsiplist6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/10-vpsiplist_host.conf"
|
||
echolog " - [$?]节点列表中的域名(vpsiplist):${fwd_dns:-默认}"
|
||
|
||
#始终用国内DNS解析直连(白名单)列表
|
||
[ -f "${RULES_PATH}/direct_host" ] && {
|
||
fwd_dns="${LOCAL_DNS}"
|
||
[ -n "$CHINADNS_NG" ] && unset fwd_dns
|
||
sort -u "${RULES_PATH}/direct_host" | gen_dnsmasq_items "whitelist,whitelist6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/11-direct_host.conf"
|
||
echolog " - [$?]域名白名单(whitelist):${fwd_dns:-默认}"
|
||
}
|
||
|
||
if [ "$(config_t_get global_subscribe subscribe_proxy 0)" = "0" ]; then
|
||
#如果没有开启通过代理订阅
|
||
fwd_dns="${LOCAL_DNS}"
|
||
for item in $(get_enabled_anonymous_secs "@subscribe_list"); do
|
||
host_from_url "$(config_n_get ${item} url)" | gen_dnsmasq_items "whitelist,whitelist6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/12-subscribe.conf"
|
||
done
|
||
echolog " - [$?]节点订阅域名(whitelist):${fwd_dns:-默认}"
|
||
else
|
||
#如果开启了通过代理订阅
|
||
fwd_dns="${TUN_DNS}"
|
||
[ -n "$CHINADNS_NG" ] && fwd_dns="${china_ng_gfw}"
|
||
for item in $(get_enabled_anonymous_secs "@subscribe_list"); do
|
||
if [ "${DNS_MODE}" = "fake_ip" ]; then
|
||
host_from_url "$(config_n_get ${item} url)" | gen_dnsmasq_fake_items "11.1.1.1" "${TMP_DNSMASQ_PATH}/91-subscribe.conf"
|
||
else
|
||
host_from_url "$(config_n_get ${item} url)" | gen_dnsmasq_items "blacklist,blacklist6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/91-subscribe.conf"
|
||
fi
|
||
done
|
||
[ "${DNS_MODE}" != "fake_ip" ] && echolog " - [$?]节点订阅域名(blacklist):${fwd_dns:-默认}"
|
||
fi
|
||
|
||
#始终使用远程DNS解析代理(黑名单)列表
|
||
[ -f "${RULES_PATH}/proxy_host" ] && {
|
||
if [ "${DNS_MODE}" = "fake_ip" ]; then
|
||
sort -u "${RULES_PATH}/proxy_host" | gen_dnsmasq_fake_items "11.1.1.1" "${TMP_DNSMASQ_PATH}/97-proxy_host.conf"
|
||
else
|
||
fwd_dns="${TUN_DNS}"
|
||
[ -n "$CHINADNS_NG" ] && fwd_dns="${china_ng_gfw}"
|
||
[ -n "$CHINADNS_NG" ] && unset fwd_dns
|
||
sort -u "${RULES_PATH}/proxy_host" | gen_dnsmasq_items "blacklist,blacklist6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/97-proxy_host.conf"
|
||
echolog " - [$?]代理域名表(blacklist):${fwd_dns:-默认}"
|
||
fi
|
||
}
|
||
|
||
#分流规则
|
||
[ "$(config_n_get $TCP_NODE protocol)" = "_shunt" ] && {
|
||
fwd_dns="${TUN_DNS}"
|
||
local default_node_id=$(config_n_get $TCP_NODE default_node _direct)
|
||
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
||
for shunt_id in $shunt_ids; do
|
||
local shunt_node_id=$(config_n_get $TCP_NODE ${shunt_id} nil)
|
||
if [ "$shunt_node_id" = "nil" ] || [ "$shunt_node_id" = "_default" ] || [ "$shunt_node_id" = "_direct" ] || [ "$shunt_node_id" = "_blackhole" ]; then
|
||
continue
|
||
fi
|
||
local shunt_node=$(config_n_get $shunt_node_id address nil)
|
||
[ "$shunt_node" = "nil" ] && continue
|
||
if [ "${DNS_MODE}" = "fake_ip" ]; then
|
||
config_n_get $shunt_id domain_list | grep -v 'regexp:\|geosite:\|ext:' | sed 's/domain:\|full:\|//g' | tr -s "\r\n" "\n" | sort -u | gen_dnsmasq_fake_items "11.1.1.1" "${TMP_DNSMASQ_PATH}/98-shunt_host.conf"
|
||
else
|
||
config_n_get $shunt_id domain_list | grep -v 'regexp:\|geosite:\|ext:' | sed 's/domain:\|full:\|//g' | tr -s "\r\n" "\n" | sort -u | gen_dnsmasq_items "shuntlist,shuntlist6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/98-shunt_host.conf"
|
||
fi
|
||
done
|
||
[ "${DNS_MODE}" != "fake_ip" ] && echolog " - [$?]Xray分流规则(shuntlist):${fwd_dns:-默认}"
|
||
}
|
||
|
||
#如果没有使用回国模式
|
||
if [ -z "${returnhome}" ]; then
|
||
[ -f "${RULES_PATH}/gfwlist" ] && {
|
||
if [ -n "$count_hosts_str" ]; then
|
||
grep -v -E "$count_hosts_str" "${RULES_PATH}/gfwlist" > "${TMP_PATH}/gfwlist"
|
||
else
|
||
cp -a "${RULES_PATH}/gfwlist" "${TMP_PATH}/gfwlist"
|
||
fi
|
||
}
|
||
if [ "${DNS_MODE}" = "fake_ip" ]; then
|
||
sort -u "${TMP_PATH}/gfwlist" | gen_dnsmasq_fake_items "11.1.1.1" "${TMP_DNSMASQ_PATH}/99-gfwlist.conf"
|
||
else
|
||
fwd_dns="${TUN_DNS}"
|
||
[ -n "$CHINADNS_NG" ] && fwd_dns="${china_ng_gfw}"
|
||
[ -n "$CHINADNS_NG" ] && unset fwd_dns
|
||
sort -u "${TMP_PATH}/gfwlist" | gen_dnsmasq_items "gfwlist,gfwlist6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/99-gfwlist.conf"
|
||
echolog " - [$?]防火墙域名表(gfwlist):${fwd_dns:-默认}"
|
||
rm -f "${TMP_PATH}/gfwlist"
|
||
fi
|
||
# Not China List 模式
|
||
[ -n "${chnlist}" ] && {
|
||
fwd_dns="${LOCAL_DNS}"
|
||
[ -n "$CHINADNS_NG" ] && unset fwd_dns
|
||
[ -f "${RULES_PATH}/chnlist" ] && {
|
||
if [ -n "$count_hosts_str" ]; then
|
||
grep -v -E "$count_hosts_str" "${RULES_PATH}/chnlist" | gen_dnsmasq_items "chnroute,chnroute6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/19-chinalist_host.conf"
|
||
else
|
||
sort -u "${RULES_PATH}/chnlist" | gen_dnsmasq_items "chnroute,chnroute6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/19-chinalist_host.conf"
|
||
fi
|
||
echolog " - [$?]中国域名表(chnroute):${fwd_dns:-默认}"
|
||
}
|
||
}
|
||
else
|
||
#回国模式
|
||
[ -f "${RULES_PATH}/chnlist" ] && {
|
||
if [ -n "$count_hosts_str" ]; then
|
||
grep -v -E "$count_hosts_str" "${RULES_PATH}/chnlist" > "${TMP_PATH}/chnlist"
|
||
else
|
||
cp -a "${RULES_PATH}/chnlist" "${TMP_PATH}/chnlist"
|
||
fi
|
||
}
|
||
if [ "${DNS_MODE}" = "fake_ip" ]; then
|
||
[ -f "${TMP_PATH}/chnlist" ] && sort -u "${TMP_PATH}/chnlist" | gen_dnsmasq_fake_items "11.1.1.1" "${TMP_DNSMASQ_PATH}/99-chinalist_host.conf"
|
||
else
|
||
fwd_dns="${TUN_DNS}"
|
||
[ -f "${TMP_PATH}/chnlist" ] && sort -u "${TMP_PATH}/chnlist" | gen_dnsmasq_items "chnroute,chnroute6" "${fwd_dns}" "${TMP_DNSMASQ_PATH}/99-chinalist_host.conf"
|
||
echolog " - [$?]中国域名表(chnroute):${fwd_dns:-默认}"
|
||
fi
|
||
rm -f "${TMP_PATH}/chnlist"
|
||
fi
|
||
|
||
#awk '{gsub(/ipset=\//,""); gsub(/\//," ");key=$1;value=$2;if (sum[key] != "") {sum[key]=sum[key]","value} else {sum[key]=sum[key]value}} END{for(i in sum) print "ipset=/"i"/"sum[i]}' "${TMP_DNSMASQ_PATH}/ipset.conf" > "${TMP_DNSMASQ_PATH}/ipset.conf2"
|
||
#mv -f "${TMP_DNSMASQ_PATH}/ipset.conf2" "${TMP_DNSMASQ_PATH}/ipset.conf"
|
||
fi
|
||
if [ "${DNS_MODE}" != "nouse" ]; then
|
||
echo "conf-dir=${TMP_DNSMASQ_PATH}" > "/var/dnsmasq.d/dnsmasq-${CONFIG}.conf"
|
||
|
||
if [ -z "${CHINADNS_NG}" ] && [ "${IS_DEFAULT_DNS}" = "1" ]; then
|
||
#echolog " - 不强制设置默认DNS"
|
||
return
|
||
else
|
||
echo "${DEFAULT_DNS}" > $TMP_PATH/default_DNS
|
||
msg="ISP"
|
||
servers="${LOCAL_DNS}"
|
||
[ -n "${chnlist}" ] && msg="中国列表以外"
|
||
[ -n "${returnhome}" ] && msg="中国列表"
|
||
[ -n "${global}" ] && msg="全局"
|
||
|
||
#默认交给Chinadns-ng处理
|
||
[ -n "$CHINADNS_NG" ] && {
|
||
servers="${china_ng_listen}" && msg="chinadns-ng"
|
||
}
|
||
|
||
cat <<-EOF >> "/var/dnsmasq.d/dnsmasq-${CONFIG}.conf"
|
||
$(echo "${servers}" | sed 's/,/\n/g' | gen_dnsmasq_items)
|
||
all-servers
|
||
no-poll
|
||
no-resolv
|
||
EOF
|
||
echolog " - [$?]以上所列以外及默认(${msg}):${servers}"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
gen_pdnsd_config() {
|
||
local listen_port=${1}
|
||
local up_dns=${2}
|
||
local pdnsd_dir=${TMP_PATH}/pdnsd
|
||
local perm_cache=2048
|
||
local _cache="on"
|
||
local query_method="tcp_only"
|
||
|
||
mkdir -p "${pdnsd_dir}"
|
||
touch "${pdnsd_dir}/pdnsd.cache"
|
||
chown -R root.nogroup "${pdnsd_dir}"
|
||
if [ "${use_udp_node_resolve_dns}" = "1" ]; then
|
||
query_method="udp_only"
|
||
else
|
||
use_tcp_node_resolve_dns=1
|
||
fi
|
||
[ "${DNS_CACHE}" = "0" ] && _cache="off" && perm_cache=0
|
||
cat > "${pdnsd_dir}/pdnsd.conf" <<-EOF
|
||
global {
|
||
perm_cache = $perm_cache;
|
||
cache_dir = "$pdnsd_dir";
|
||
run_as = "root";
|
||
server_ip = 127.0.0.1;
|
||
server_port = ${listen_port};
|
||
status_ctl = on;
|
||
query_method = ${query_method};
|
||
min_ttl = 1h;
|
||
max_ttl = 1w;
|
||
timeout = 10;
|
||
par_queries = 2;
|
||
neg_domain_pol = on;
|
||
udpbufsize = 1024;
|
||
proc_limit = 2;
|
||
procq_limit = 8;
|
||
}
|
||
|
||
EOF
|
||
echolog " + [$?]Pdnsd (127.0.0.1:${listen_port})..."
|
||
|
||
append_pdnsd_updns() {
|
||
[ -z "${2}" ] && echolog " | - 略过错误 : ${1}" && return 0
|
||
cat >> $pdnsd_dir/pdnsd.conf <<-EOF
|
||
server {
|
||
label = "node-${2}_${3}";
|
||
ip = ${2};
|
||
edns_query = on;
|
||
port = ${3};
|
||
timeout = 4;
|
||
interval = 10m;
|
||
uptest = none;
|
||
purge_cache = off;
|
||
proxy_only = on;
|
||
caching = $_cache;
|
||
reject = ::/0;
|
||
reject_policy = negate;
|
||
}
|
||
EOF
|
||
echolog " | - [$?]上游DNS:${2}:${3}"
|
||
}
|
||
hosts_foreach up_dns append_pdnsd_updns 53
|
||
}
|
||
|
||
del_dnsmasq() {
|
||
rm -rf /var/dnsmasq.d/dnsmasq-$CONFIG.conf
|
||
rm -rf $DNSMASQ_PATH/dnsmasq-$CONFIG.conf
|
||
rm -rf $TMP_DNSMASQ_PATH
|
||
}
|
||
|
||
add_ip2route() {
|
||
local ip=$(get_host_ip "ipv4" $1)
|
||
[ -z "$ip" ] && {
|
||
echolog " - 无法解析${1},路由表添加失败!"
|
||
return 1
|
||
}
|
||
local remarks="${1}"
|
||
[ "$remarks" != "$ip" ] && remarks="${1}(${ip})"
|
||
local interface=$2
|
||
local retries=5
|
||
local failcount=0
|
||
while [ "$failcount" -lt $retries ]; do
|
||
unset msg
|
||
ip route show dev ${interface} >/dev/null 2>&1
|
||
if [ $? -ne 0 ]; then
|
||
let "failcount++"
|
||
echolog " - 找不到出口接口:$interface,1分钟后再重试(${failcount}/${retries}),${ip}"
|
||
[ "$failcount" -ge $retries ] && return 1
|
||
sleep 1m
|
||
else
|
||
route add -host ${ip} dev ${interface} >/dev/null 2>&1
|
||
echolog " - ${remarks}添加路由表${interface}接口成功!"
|
||
echo "$ip" >> $TMP_ROUTE_PATH/${interface}
|
||
break
|
||
fi
|
||
done
|
||
}
|
||
|
||
delete_ip2route() {
|
||
[ -d "${TMP_ROUTE_PATH}" ] && {
|
||
for interface in $(ls ${TMP_ROUTE_PATH}); do
|
||
for ip in $(cat ${TMP_ROUTE_PATH}/${interface}); do
|
||
route del -host ${ip} dev ${interface} >/dev/null 2>&1
|
||
done
|
||
done
|
||
}
|
||
}
|
||
|
||
start_haproxy() {
|
||
local haproxy_path haproxy_file item items lport sort_items
|
||
|
||
[ "$(config_t_get global_haproxy balancing_enable 0)" != "1" ] && return
|
||
echolog "HAPROXY 负载均衡..."
|
||
|
||
haproxy_path=${TMP_PATH}/haproxy
|
||
mkdir -p "${haproxy_path}"
|
||
haproxy_file=${haproxy_path}/config.cfg
|
||
cat <<-EOF > "${haproxy_file}"
|
||
global
|
||
log 127.0.0.1 local2
|
||
chroot ${haproxy_path}
|
||
maxconn 60000
|
||
stats socket ${haproxy_path}/haproxy.sock
|
||
daemon
|
||
|
||
defaults
|
||
mode tcp
|
||
log global
|
||
option tcplog
|
||
option dontlognull
|
||
option http-server-close
|
||
#option forwardfor except 127.0.0.0/8
|
||
option redispatch
|
||
retries 2
|
||
timeout http-request 10s
|
||
timeout queue 1m
|
||
timeout connect 10s
|
||
timeout client 1m
|
||
timeout server 1m
|
||
timeout http-keep-alive 10s
|
||
timeout check 10s
|
||
maxconn 3000
|
||
|
||
EOF
|
||
|
||
items=$(get_enabled_anonymous_secs "@haproxy_config")
|
||
for item in $items; do
|
||
lport=$(config_n_get ${item} haproxy_port 0)
|
||
[ "${lport}" = "0" ] && echolog " - 丢弃1个明显无效的节点" && continue
|
||
sort_items="${sort_items}${IFS}${lport} ${item}"
|
||
done
|
||
|
||
items=$(echo "${sort_items}" | sort -n | cut -d ' ' -sf 2)
|
||
|
||
unset lport
|
||
local haproxy_port lbss lbort lbweight export backup
|
||
local msg bip bport hasvalid bbackup failcount interface
|
||
for item in ${items}; do
|
||
unset haproxy_port lbort bbackup
|
||
|
||
eval $(uci -q show "${CONFIG}.${item}" | cut -d '.' -sf 3-)
|
||
get_ip_port_from "$lbss" bip bport
|
||
|
||
[ "$lbort" = "default" ] && lbort=$bport || bport=$lbort
|
||
[ -z "$haproxy_port" ] || [ -z "$bip" ] || [ -z "$lbort" ] && echolog " - 丢弃1个明显无效的节点" && continue
|
||
[ "$backup" = "1" ] && bbackup="backup"
|
||
|
||
[ "$lport" = "${haproxy_port}" ] || {
|
||
hasvalid="1"
|
||
lport=${haproxy_port}
|
||
echolog " + 入口 0.0.0.0:${lport}..."
|
||
cat <<-EOF >> "${haproxy_file}"
|
||
listen $lport
|
||
mode tcp
|
||
bind 0.0.0.0:$lport
|
||
EOF
|
||
}
|
||
|
||
cat <<-EOF >> "${haproxy_file}"
|
||
server $bip:$bport $bip:$bport weight $lbweight check inter 1500 rise 1 fall 3 $bbackup
|
||
EOF
|
||
|
||
if [ "$export" != "0" ]; then
|
||
add_ip2route ${bip} ${export} > /dev/null 2>&1 &
|
||
fi
|
||
echolog " | - 出口节点:${bip}:${bport},权重:${lbweight}"
|
||
done
|
||
|
||
# 控制台配置
|
||
local console_port=$(config_t_get global_haproxy console_port)
|
||
local console_user=$(config_t_get global_haproxy console_user)
|
||
local console_password=$(config_t_get global_haproxy console_password)
|
||
local auth=""
|
||
[ -n "$console_user" ] && [ -n "$console_password" ] && auth="stats auth $console_user:$console_password"
|
||
cat <<-EOF >> "${haproxy_file}"
|
||
|
||
listen console
|
||
bind 0.0.0.0:$console_port
|
||
mode http
|
||
stats refresh 30s
|
||
stats uri /
|
||
stats admin if TRUE
|
||
$auth
|
||
EOF
|
||
|
||
[ "${hasvalid}" != "1" ] && echolog " - 没有发现任何有效节点信息,不启动。" && return 0
|
||
ln_start_bin "$(first_type haproxy)" haproxy "/dev/null" -f "${haproxy_file}"
|
||
echolog " * 控制台端口:${console_port}/,${auth:-公开}"
|
||
}
|
||
|
||
kill_all() {
|
||
kill -9 $(pidof "$@") >/dev/null 2>&1
|
||
}
|
||
|
||
force_stop() {
|
||
stop
|
||
exit 0
|
||
}
|
||
|
||
backup_dnsmasq_servers() {
|
||
DNSMASQ_DNS=$(uci show dhcp | grep "@dnsmasq" | grep ".server=" | awk -F '=' '{print $2}' | sed "s/'//g" | tr ' ' ',')
|
||
if [ -n "${DNSMASQ_DNS}" ]; then
|
||
uci -q set $CONFIG.@global[0].dnsmasq_servers="${DNSMASQ_DNS}"
|
||
uci commit $CONFIG
|
||
fi
|
||
}
|
||
|
||
restore_dnsmasq_servers() {
|
||
OLD_SERVER=$(uci -q get $CONFIG.@global[0].dnsmasq_servers | tr "," " ")
|
||
for server in $OLD_SERVER; do
|
||
uci -q del_list dhcp.@dnsmasq[0].server=$server
|
||
uci add_list dhcp.@dnsmasq[0].server=$server
|
||
done
|
||
uci commit dhcp
|
||
uci -q delete $CONFIG.@global[0].dnsmasq_servers
|
||
uci commit $CONFIG
|
||
}
|
||
|
||
restart_dnsmasq() {
|
||
if [ -f "$TMP_PATH/default_DNS" ]; then
|
||
backup_dnsmasq_servers
|
||
sed -i "/list server/d" /etc/config/dhcp >/dev/null 2>&1
|
||
/etc/init.d/dnsmasq restart >/dev/null 2>&1
|
||
restore_dnsmasq_servers
|
||
else
|
||
/etc/init.d/dnsmasq restart >/dev/null 2>&1
|
||
fi
|
||
}
|
||
|
||
boot() {
|
||
[ "$ENABLED" == 1 ] && {
|
||
local delay=$(config_t_get global_delay start_delay 1)
|
||
if [ "$delay" -gt 0 ]; then
|
||
echolog "执行启动延时 $delay 秒后再启动!"
|
||
sleep $delay && start >/dev/null 2>&1 &
|
||
else
|
||
start
|
||
fi
|
||
}
|
||
return 0
|
||
}
|
||
|
||
start() {
|
||
#加锁防止并发开启服务
|
||
set_lock
|
||
load_config
|
||
start_haproxy
|
||
[ "$SOCKS_ENABLED" = "1" ] && {
|
||
start_socks
|
||
}
|
||
[ "$NO_PROXY" == 1 ] || {
|
||
start_redir TCP
|
||
start_redir UDP
|
||
start_dns
|
||
add_dnsmasq
|
||
source $APP_PATH/iptables.sh start
|
||
restart_dnsmasq
|
||
echolog "重启 dnsmasq 服务[$?]"
|
||
}
|
||
start_crontab
|
||
echolog "运行完成!\n"
|
||
unset_lock
|
||
}
|
||
|
||
stop() {
|
||
unlock
|
||
set_lock
|
||
clean_log
|
||
source $APP_PATH/iptables.sh stop
|
||
delete_ip2route
|
||
kill_all v2ray-plugin obfs-local
|
||
top -bn1 | grep -v "grep" | grep "sleep" | grep -E "9s|58s" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||
top -bn1 | grep -v "grep" | grep -v "app.sh" | grep "${CONFIG}/" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||
rm -rf $TMP_DNSMASQ_PATH $TMP_PATH
|
||
unset XRAY_LOCATION_ASSET
|
||
stop_crontab
|
||
del_dnsmasq
|
||
/etc/init.d/dnsmasq restart >/dev/null 2>&1
|
||
echolog "重启 dnsmasq 服务[$?]"
|
||
echolog "清空并关闭相关程序和缓存完成。"
|
||
unset_lock
|
||
}
|
||
|
||
arg1=$1
|
||
shift
|
||
case $arg1 in
|
||
get_new_port)
|
||
get_new_port $@
|
||
;;
|
||
run_socks)
|
||
run_socks $@
|
||
;;
|
||
run_redir)
|
||
run_redir $@
|
||
;;
|
||
node_switch)
|
||
node_switch $@
|
||
;;
|
||
stop)
|
||
[ "$1" = "force" ] && force_stop
|
||
stop
|
||
;;
|
||
start)
|
||
start
|
||
;;
|
||
boot)
|
||
boot
|
||
;;
|
||
esac
|