#!/bin/bash
# hiboy改 原项目地址: https://github.com/zfl9/ss-tproxy
source /etc/storage/script/init.sh
source /etc/storage/app_26.sh
source /etc/storage/app_27.sh

trap "exit 1" HUP INT QUIT TERM PIPE

# 载入iptables模块
for module in ip_set ip_set_bitmap_ip ip_set_bitmap_ipmac ip_set_bitmap_port ip_set_hash_ip ip_set_hash_ipport ip_set_hash_ipportip ip_set_hash_ipportnet ip_set_hash_net ip_set_hash_netport ip_set_list_set xt_set xt_TPROXY
do
	modprobe $module
done 
if [ ! -d /opt/app/ss_tproxy ] ; then
	logger -t "【clash】" "找不到 /opt/app/ss_tproxy ，安装 opt 程序"
	/etc/storage/script/Sh01_mountopt.sh start
	mkdir -p /opt/app/ss_tproxy
fi

ss_tproxy_config='/etc/storage/app_27.sh'
echo "$dnsmasq_conf_dir
/opt/app/ss_tproxy/tmp
/opt/app/ss_tproxy/conf
/opt/app/ss_tproxy/rule
/opt/app/ss_tproxy/dnsmasq.d
/tmp/ss_tproxy/dnsmasq.d" | while read dir_name; do [ ! -z "$dir_name" ] && [ ! -d "$dir_name" ] && mkdir -p $dir_name ; done 
echo "$dnsmasq_conf_file
$proxy_all_svraddr
$proxy_svraddr4
$proxy_svraddr6
$dnsmasq_conf_string
$file_gfwlist_txt
$file_gfwlist_ext
$file_ignlist_ext
$file_lanlist_ext
$file_wanlist_ext
$file_chnroute_txt
$file_chnroute6_txt
$file_chnroute_set
$file_chnroute6_set" | while read file_name; do [ ! -z "$file_name" ] && [ ! -f "$file_name" ] && touch $file_name ; done

if [ -n "$LAN_AC_IP" ] ; then
	case "${LAN_AC_IP:0:1}" in
		0)
			LAN_TARGET="SSTP_WAN_AC"
			;;
		1)
			LAN_TARGET="SSTP_WAN_FW"
			;;
		2)
			LAN_TARGET="SSTP_WAN_AC"
			#LAN_TARGET="RETURN"
			;;
	esac
fi

IPV4_RESERVED_IPADDRS="
0.0.0.0/8
10.0.0.0/8
100.64.0.0/10
127.0.0.0/8
169.254.0.0/16
172.16.0.0/12
192.0.0.0/24
192.0.2.0/24
192.88.99.0/24
192.168.0.0/16
198.18.0.0/15
198.51.100.0/24
203.0.113.0/24
224.0.0.0/4
240.0.0.0/4
255.255.255.255/32
100.100.100.100/32
188.188.188.188/32
110.110.110.110/32
"

IPV6_RESERVED_IPADDRS="
::/128
::1/128
::ffff:0:0/96
::ffff:0:0:0/96
64:ff9b::/96
100::/64
2001::/32
2001:20::/28
2001:db8::/32
2002::/16
fc00::/7
fe80::/10
ff00::/8
"

font_bold() {
	printf "\e[1m$*\e[0m"
}

color_red() {
	printf "\e[35m$*\e[0m"
}

color_green() {
	printf "\e[32m$*\e[0m"
}

color_yellow() {
	printf "\e[31m$*\e[0m"
}

log_error() {
	logger -t "【sh_ss_tproxy.sh】" "【错误】""$*"
	logger -t "【sh_ss_tproxy.sh】" "【错误】""出错了？试试手动重置 ss_tproxy 数据"
	echo "$(font_bold $(color_yellow '[ERROR]')) $*" 1>&2
	stop
	exit 1
}

is_true() {
	[ "$1" = 'true' ]
}

is_false() {
	[ "$1" = 'false' ]
}

file_is_exists() {
	[ -f "$1" ]
}

command_is_exists() {
	#command -v "$1" &>/dev/null
	hash "$1" 2>/dev/null
}

process_is_running() {
	kill -0 "$1" &>/dev/null
}

tcp_port_is_exists() {
	[ $($netstat -lnpt | grep -E ":$1[ \t]" | wc -l) -ne 0 ]
}

udp_port_is_exists() {
	[ $($netstat -anpu | grep -E ":$1[ \t]" | wc -l) -ne 0 ]
}

ss_tproxy_is_started() {
#    process_is_running "$status_dnsmasq_pid"  ||
#	process_is_running "$status_chinadns_pid" ||
#	process_is_running "$status_dns2tcp4_pid" ||
#	process_is_running "$status_dns2tcp6_pid" ||
	iptables  -t mangle -nL SSTP_OUTPUT &>/dev/null ||
	iptables  -t nat    -nL SSTP_OUTPUT &>/dev/null ||
	ip6tables -t mangle -nL SSTP_OUTPUT &>/dev/null ||
	ip6tables -t nat    -nL SSTP_OUTPUT &>/dev/null ||
	[ $(ip -4 route show table $ipts_rt_tab 2>/dev/null | wc -l) -ne 0 ] ||
	[ $(ip -6 route show table $ipts_rt_tab 2>/dev/null | wc -l) -ne 0 ] ||
	[ $(ip -4 rule 2>/dev/null | grep -c "fwmark $ipts_rt_mark") -ne 0 ] ||
	[ $(ip -6 rule 2>/dev/null | grep -c "fwmark $ipts_rt_mark") -ne 0 ]
}

is_ipv4_ipts() {
	[ "$1" = 'iptables' ]
}

is_ipv6_ipts() {
	[ "$1" = 'ip6tables' ]
}

is_global_mode() {
	[ "$mode" = 'global' ]
}

is_chnlist_mode() {
	[ "$mode" = 'chnlist' ]
}

is_gfwlist_mode() {
	[ "$mode" = 'gfwlist' ]
}

is_chnroute_mode() {
	[ "$mode" = 'chnroute' ]
}

is_enabled_udp() {
	is_false "$tcponly"
}

is_need_iproute() {
	is_true "$tproxy" || is_enabled_udp
}

is_usrgrp_mode() {
    [ "$uid_owner" != "0" ] || [ "$gid_owner" != "0" ]
}

get_usrgrp_args() {
    if [ "$uid_owner" != "0" ] && [ "$gid_owner" != "0" ]; then
        echo "--uid-owner $uid_owner --gid-owner $gid_owner"
    elif [ "$uid_owner" != "0" ]; then
        echo "--uid-owner $uid_owner"
    elif [ "$gid_owner" != "0" ]; then
        echo "--gid-owner $gid_owner"
    fi
}

is_nonstd_dnsport() {
	[ "$1" != '53' ]
}

is_empty_iptschain() {
	ipts="$1" ; table="$2" ; chain="$3"
	[ $($ipts -t $table -nvL $chain --line-numbers | grep -Ec '^[0-9]') -eq 0 ]
}

is_ipv4_address() {
	[ $(echo "$1" | grep -Ec '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$') -ne 0 ]
}

is_ipv6_address() {
	[ $(echo "$1" | grep -c ':') -ne 0 ]
}

is_domain_name() {
	! is_ipv4_address "$1" && ! is_ipv6_address "$1"
}

is_md5_ok() {
	[ "$md5_check" == "OK" ]
}

is_md5_not() {
	[ "$md5_check" == "NOT" ]
}

set_sysctl_option() {
	option_name="$1" ; option_value="$2"
	if command_is_exists "sysctl"; then
		sysctl -w "$option_name=$option_value" >/dev/null
	else
		option_path="/proc/sys/${option_name//.//}"
		echo "$option_value" >$option_path
	fi
}

resolve_hostname_by_hosts() {
	cat /etc/hosts /etc/storage/dnsmasq/hosts | sed 's/#.*//g' | grep -v '^$' | grep -F "$1" | head -n1 | awk '{print $1}'
}

resolve_hostname_by_doh() {
	addr_family="$1" ; hostname="$2"
	ipaddr=$(resolve_hostname_by_hosts "$hostname")
	if [ "$ipaddr" ]; then
		if [ "$addr_family" = '-4' ] ; then
			ipaddr=$(echo "$ipaddr" | grep -v ":" | head -n1)
			is_ipv4_address "$ipaddr" && echo "$ipaddr"
			return
		fi
		if [ "$addr_family" = '-6' ] ; then
			ipaddr=$(echo "$ipaddr" | grep ':' | head -n1)
			is_ipv6_address "$ipaddr" && echo "$ipaddr"
			return
		fi
	fi
	[ "$addr_family" = '-4' ] && arNslookup "$hostname" || arNslookup6 "$hostname"
}

resolve_hostname_by_dig() {
	addr_family="$1" ; hostname="$2"
	ipaddr=$(resolve_hostname_by_hosts "$hostname")
	if [ "$ipaddr" ]; then
		if [ "$addr_family" = '-4' ] && is_ipv4_address "$ipaddr"; then
			echo "$ipaddr"
			return
		fi
		if [ "$addr_family" = '-6' ] && is_ipv6_address "$ipaddr"; then
			echo "$ipaddr"
			return
		fi
	fi
	[ "$addr_family" = '-4' ] && dns_qtype='A' || dns_qtype='AAAA'
	dig +short "$dns_qtype" "$hostname" | grep -Ev '^;|\.$' | head -n1
}

resolve_hostname_by_getent() {
	addr_family="$1" ; hostname="$2"
	[ "$addr_family" = '-4' ] && db_name='ahostsv4' || db_name='ahostsv6'
	getent "$db_name" "$hostname" | head -n1 | awk '{print $1}'
}

resolve_hostname_by_ping() {
	addr_family="$1" ; hostname="$2"
	[ "$addr_family" = '-4' ] && ping_cmd="$ping4" || ping_cmd="$ping6"
	$ping_cmd -nq -c1 -w1 -W1 "$hostname" | head -n1 | sed -r 's/\(|\)/|/g' | awk -F'|' '{print $2}'
}

resolve_hostname4() {
	ipaddr=""
	i_timeout=1
	while [ -z "$ipaddr" ]; do
		ipaddr=$($resolver_func -4 "$1")
		[ -z "$ipaddr" ] && usleep 300000
		i_timeout=`expr $i_timeout + 1`
		if [ "$i_timeout" -gt 2 ] ; then
			break
		fi
	done
	is_ipv4_address "$ipaddr" && echo "$ipaddr"
}

resolve_hostname6() {
	ipaddr=""
	i_timeout=1
	while [ -z "$ipaddr" ]; do
		ipaddr=$($resolver_func -6 "$1")
		[ -z "$ipaddr" ] && usleep 300000
		i_timeout=`expr $i_timeout + 1`
		if [ "$i_timeout" -gt 2 ] ; then
			break
		fi
	done
	is_ipv6_address "$ipaddr" && echo "$ipaddr"
}

resolve_svraddr() {
	update_dnsmasq_file
	if [ "$uid_owner" == "0" ] && [ "$gid_owner" == "0" ] ; then
	
	while read svraddr; do
		[ -z "$svraddr" ] && continue
		[ ! -z "$(echo $svraddr | grep 8.8.8.8)$(echo $svraddr | grep 114.114.114.114)$(echo $svraddr | grep 119.29.29.29)$(echo $svraddr | grep 223.5.5.5)" ] && continue
		[ ! -z "$(cat $file_wanlist_ext | grep -E "^@g" | cut -c4- | grep "$svraddr")" ] && continue
		if is_true "$ipv4"; then
			is_ipv6_address "$svraddr" && continue
			is_ipv4_address "$svraddr" && svrip_all="$svraddr" || svrip_all=$(resolve_hostname4 "$svraddr")
			is_ipv4_address "$svrip_all" && [ -z "$(grep $svrip_all $proxy_svraddr4)" ] && echo "$svrip_all" >> $proxy_svraddr4
		fi
		
		if is_true "$ipv6"; then
			is_ipv4_address "$svraddr" && continue
			is_ipv6_address "$svraddr" && svrip_all="$svraddr" || svrip_all=$(resolve_hostname6 "$svraddr")
			is_ipv6_address "$svrip_all" && [ -z "$(grep $svrip_all $proxy_svraddr6)" ] && echo "$svrip_all" >> $proxy_svraddr6
		fi
	done < $proxy_all_svraddr
	fi

#ipset destroy $setname &>/dev/null
ipset flush proxyaddr &>/dev/null
ipset flush proxyaddr6 &>/dev/null
ipset flush localaddr &>/dev/null
ipset flush localaddr6 &>/dev/null
ipset flush privaddr &>/dev/null
ipset flush privaddr6 &>/dev/null

echo "create proxyaddr hash:net hashsize 64 family inet
create proxyaddr6 hash:net hashsize 64 family inet6
create chnroute hash:net hashsize 1024 family inet
create chnroute6 hash:net hashsize 1024 family inet6
create gfwlist hash:net hashsize 1024 family inet
create gfwlist6 hash:net hashsize 1024 family inet6
create adbybylist hash:net hashsize 1024 family inet
create localaddr hash:net hashsize 64 family inet
create localaddr6 hash:net hashsize 64 family inet6
create privaddr hash:net hashsize 64 family inet
create privaddr6 hash:net hashsize 64 family inet6
create sstp_dst_bp hash:net hashsize 64 family inet
create sstp_dst_bp6 hash:net hashsize 64 family inet6
create sstp_dst_fw hash:net hashsize 64 family inet
create sstp_dst_fw6 hash:net hashsize 64 family inet6
create sstp_dst_dns_fw hash:net hashsize 64 family inet
create sstp_dst_dns_fw6 hash:net hashsize 64 family inet6
create sstp_src_ac hash:net hashsize 64 family inet
create sstp_src_ac6 hash:net hashsize 64 family inet6
create sstp_src_bp hash:net hashsize 64 family inet
create sstp_src_bp6 hash:net hashsize 64 family inet6
create sstp_src_fw hash:net hashsize 64 family inet
create sstp_src_fw6 hash:net hashsize 64 family inet6
create sstp_src_gfw hash:net hashsize 64 family inet
create sstp_src_gfw6 hash:net hashsize 64 family inet6
create sstp_src_chn hash:net hashsize 64 family inet
create sstp_src_chn6 hash:net hashsize 64 family inet6
create sstp_mac_ac hash:mac hashsize 64
create sstp_mac_bp hash:mac hashsize 64
create sstp_mac_fw hash:mac hashsize 64
create sstp_mac_gfw hash:mac hashsize 64
create sstp_mac_chn hash:mac hashsize 64" | while read sstp_name; do ipset -! $sstp_name ; done 

	ipset flush proxyaddr &>/dev/null
	ipset flush proxyaddr6 &>/dev/null
	proxy_svripv4="$(cat $proxy_svraddr4)"
	[ ! -z "$proxy_svripv4" ] && { for svr_ip in $proxy_svripv4; do echo "-A proxyaddr $svr_ip"; done | ipset -! restore &>/dev/null ; }
	proxy_svripv6="$(cat $proxy_svraddr6)"
	[ ! -z "$proxy_svripv6" ] && { for svr_ip in $proxy_svripv6; do echo "-A proxyaddr6 $svr_ip"; done | ipset -! restore &>/dev/null ; }
	ipset flush localaddr &>/dev/null
	ipset flush localaddr6 &>/dev/null
	ifconfig -a | grep inet | grep -v inet6 | awk '{print $2}' | tr -d "addr:"​ | while read ip_addr; do echo "-A localaddr $ip_addr"; done | ipset -! restore &>/dev/null
	ifconfig -a | grep inet6 | awk '{print $3}' | while read ip_addr; do echo "-A localaddr6 $ip_addr"; done | ipset -! restore &>/dev/null
	ipset flush privaddr &>/dev/null
	ipset flush privaddr6 &>/dev/null
	for priv_ip in $IPV4_RESERVED_IPADDRS; do echo "-A privaddr $priv_ip"; done | ipset -! restore &>/dev/null
	cat $file_ignlist_ext | grep -E "^-" | cut -c2- | while read ip_addr; do echo "-A privaddr $ip_addr"; done | ipset -! restore &>/dev/null
	for priv_ip in $IPV6_RESERVED_IPADDRS; do echo "-A privaddr6 $priv_ip"; done | ipset -! restore &>/dev/null
	cat $file_ignlist_ext | grep -E "^~" | cut -c2- | while read ip_addr; do echo "-A privaddr6 $ip_addr"; done | ipset -! restore &>/dev/null


}

waiting_network() {
	[ -z "$1" ] && return
	is_ipv4_address "$1" && ping_cmd="$ping4" || ping_cmd="$ping6"
	until $ping_cmd -nq -c1 -W1 "$1" >/dev/null; do
		echo "waiting for network available..."
		sleep 1
	done
}

load_pidfile() {
	source "$file_dnsserver_pid" || log_error "load pidfile failed, exit-code: $?"
}

update_pidfile() {
echo "update_pidfile"
#	echo "status_dnsmasq_pid=$status_dnsmasq_pid"    >$file_dnsserver_pid
#	echo "status_chinadns_pid=$status_chinadns_pid"  >$file_dnsserver_pid
#	echo "status_dns2tcp4_pid=$status_dns2tcp4_pid" >>$file_dnsserver_pid
#	echo "status_dns2tcp6_pid=$status_dns2tcp6_pid" >>$file_dnsserver_pid
}

delete_pidfile() {
	rm -f $file_dnsserver_pid &>/dev/null
}

load_config() {
	if ! file_is_exists "$ss_tproxy_config"; then
		log_error "file not found: $ss_tproxy_config"
	else
		source "$ss_tproxy_config" $arguments || log_error "load config failed, exit-code: $?"
	fi

	for optentry in $optentries; do eval "$optentry"; done

	[ -z "$uid_owner" ] && uid_owner="0"
	[ -z "$gid_owner" ] && gid_owner="0"

	# MODE_TARGET
	if is_global_mode; then
		MODE_TARGET="SSTP_WAN_FW"
	fi
	if is_chnroute_mode; then
		MODE_TARGET="SSTP_WAN_CHN"
		GFWLIST_TARGET="SSTP_WAN_FW"
		CHN_TARGET="RETURN"
		CHN_WAN_TARGET="SSTP_WAN_FW"
	fi
	if is_gfwlist_mode; then
		MODE_TARGET="SSTP_WAN_GFW"
		GFWLIST_TARGET="SSTP_WAN_FW"
		CHN_TARGET="RETURN"
		CHN_WAN_TARGET="SSTP_WAN_FW"
	fi
	if is_chnlist_mode; then
		MODE_TARGET="SSTP_GFW_CHN"
		GFWLIST_TARGET="SSTP_WAN_FW"
		CHN_TARGET="SSTP_WAN_FW"
		CHN_WAN_TARGET="RETURN"
	fi

	# update_wanlanlist_ipset 规则处理标签
	if is_true "$ipv4" && is_true "$ipv6"; then
		gfwlist_ipset_setname="gfwlist,gfwlist6"
		sstp_dst_fw_ipset_setname="sstp_dst_fw,sstp_dst_fw6"
		sstp_dst_dns_fw_ipset_setname="sstp_dst_dns_fw,sstp_dst_dns_fw6"
		sstp_dst_bp_ipset_setname="sstp_dst_bp,sstp_dst_bp6"
	elif is_true "$ipv4"; then
		gfwlist_ipset_setname="gfwlist"
		sstp_dst_fw_ipset_setname="sstp_dst_fw"
		sstp_dst_dns_fw_ipset_setname="sstp_dst_dns_fw"
		sstp_dst_bp_ipset_setname="sstp_dst_bp"
	else
		gfwlist_ipset_setname="gfwlist6"
		sstp_dst_fw_ipset_setname="sstp_dst_fw6"
		sstp_dst_dns_fw_ipset_setname="sstp_dst_dns_fw6"
		sstp_dst_bp_ipset_setname="sstp_dst_bp6"
	fi
	if is_chnlist_mode; then # 回国模式 反转 wanlist 规则， china DNS 需要走代理
		dst_fw_ipset_type="$sstp_dst_bp_ipset_setname"
		dst_dns_fw_ipset_type="$sstp_dst_bp_ipset_setname"
		dst_bp_ipset_type="$sstp_dst_fw_ipset_setname"
		dst4_fw_type="sstp_dst_bp"
		dst6_fw_type="sstp_dst_bp6"
		dst4_dns_fw_type="sstp_dst_bp"
		dst6_dns_fw_type="sstp_dst_bp6"
		dst4_bp_type="sstp_dst_fw"
		dst6_bp_type="sstp_dst_fw6"
		dns4_fw_type="$dns_direct"
		dns6_fw_type="$dns_direct6"
		dns4_bp_type="$dns_remote"
		dns6_bp_type="$dns_remote6"
	else
		dst_fw_ipset_type="$sstp_dst_fw_ipset_setname"
		dst_dns_fw_ipset_type="$sstp_dst_dns_fw_ipset_setname"
		dst_bp_ipset_type="$sstp_dst_bp_ipset_setname"
		dst4_fw_type="sstp_dst_fw"
		dst6_fw_type="sstp_dst_fw6"
		dst4_dns_fw_type="sstp_dst_dns_fw"
		dst6_dns_fw_type="sstp_dst_dns_fw6"
		dst4_bp_type="sstp_dst_bp"
		dst6_bp_type="sstp_dst_bp6"
		dns4_fw_type="127.0.0.1#8053"
		dns6_fw_type="$dns_remote6"
		dns4_bp_type="$dns_direct"
		dns6_bp_type="$dns_direct6"
	fi

	# ss_tproxy 配置文件的配置参数覆盖 web 的配置参数
	dns_start_dnsproxy=`nvram get app_112`
	[ -z $dns_start_dnsproxy ] && dns_start_dnsproxy=0 && nvram set app_112=0
	[ ! -z "$ext_dns_start_dnsproxy" ] && dns_start_dnsproxy="$ext_dns_start_dnsproxy"
	
	ss_dnsproxy_x=`nvram get ss_dnsproxy_x`
	[ -z $ss_dnsproxy_x ] && ss_dnsproxy_x=0 && nvram set ss_dnsproxy_x=0
	[ ! -z "$ext_ss_dnsproxy_x" ] && ss_dnsproxy_x="$ext_ss_dnsproxy_x"
	
	ss_pdnsd_all=`nvram get ss_pdnsd_all`
	[ -z $ss_pdnsd_all ] && ss_pdnsd_all=0 && nvram set ss_pdnsd_all=0
	[ ! -z "$ext_ss_pdnsd_all" ] && ss_pdnsd_all="$ext_ss_pdnsd_all"
	
	ss_pdnsd_cn_all=`nvram get app_113`
	[ -z $ss_pdnsd_cn_all ] && ss_pdnsd_cn_all=0 && nvram set app_113=0
	[ ! -z "$ext_ss_pdnsd_cn_all" ] && ss_pdnsd_cn_all="$ext_ss_pdnsd_cn_all"
	
	output_return=`nvram get app_114`
	[ -z $output_return ] && output_return=0 && nvram set app_114=0
	[ ! -z "$ext_output_return" ] && output_return="$ext_output_return"
	
	output_udp_return=`nvram get ss_udp_enable`
	[ -z $output_udp_return ] && output_udp_return=0 && nvram set ss_udp_enable=0
	[ ! -z "$ext_output_udp_return" ] && output_udp_return="$ext_output_udp_return"
	
	ss_all_udp=`nvram get app_81`
	[ -z $ss_all_udp ] && ss_all_udp=0 && nvram set app_81=0
	[ ! -z "$ext_ss_all_udp" ] && ss_all_udp="$ext_ss_all_udp"
}

check_config() {
	file_is_exists "$file_gfwlist_txt"   || log_error "file not found: $file_gfwlist_txt"
	file_is_exists "$file_gfwlist_ext"   || log_error "file not found: $file_gfwlist_ext"
	file_is_exists "$file_ignlist_ext"   || log_error "file not found: $file_ignlist_ext"
	file_is_exists "$file_chnroute_set"  || log_error "file not found: $file_chnroute_set"
	file_is_exists "$file_chnroute6_set" || log_error "file not found: $file_chnroute6_set"
	#file_is_exists "$file_dnsserver_pid" && load_pidfile

	{ ! is_global_mode && ! is_gfwlist_mode && ! is_chnroute_mode && ! is_chnlist_mode; } && log_error "the value of the mode option is invalid: $mode"

	{ is_false "$ipv4" && is_false "$ipv6"; } && log_error "both ipv4 and ipv6 are disabled, nothing to do"

	[ -z "$proxy_svrport" ] && log_error "the value of the proxy_svrport option is empty: $proxy_svrport"
	#if [ "$uid_owner" == "0" ] && [ "$gid_owner" == "0" ] ; then
		#[ -z "$(cat $proxy_svraddr4)" ] && [ -z "$(cat $proxy_svraddr6)" ] && log_error "both proxy_svraddr4 and proxy_svraddr6 are empty"
	#fi

	command_is_exists 'ipset'   || log_error "command not found: ipset"
	command_is_exists 'dnsmasq' || log_error "command not found: dnsmasq"
	is_need_iproute && { command_is_exists 'ip' || log_error "command not found: ip"; }
	is_true "$ipv4" && { command_is_exists 'iptables'  || log_error "command not found: iptables";  }
	is_true "$ipv6" && { command_is_exists 'ip6tables' || log_error "command not found: ip6tables"; }
#	is_chnroute_mode && { command_is_exists 'chinadns_ng' || log_error "command not found: chinadns_ng"; }
#	! is_enabled_udp && { command_is_exists "dns2tcp" || log_error "command not found: dns2tcp"; }

	case "$opts_ss_netstat" in
		auto)
			if command_is_exists 'ss'; then
				netstat='ss'
			elif command_is_exists 'netstat'; then
				netstat='netstat'
			else
				log_error "command not found: ss/netstat"
			fi
			;;
		ss)
			command_is_exists 'ss' && netstat='ss' || log_error "command not found: ss"
			;;
		netstat)
			command_is_exists 'netstat' && netstat='netstat' || log_error "command not found: netstat"
			;;
		*)
			log_error "the value of the opts_ss_netstat option is invalid: $opts_ss_netstat"
			;;
	esac

	case "$opts_ping_cmd_to_use" in
		auto)
			if command_is_exists 'ping' && command_is_exists 'ping6'; then
				ping4='ping'; ping6='ping6'
			elif command_is_exists 'ping'; then
				ping4='ping -4'; ping6='ping -6'
			else
				log_error "command not found: ping/ping6"
			fi
			;;
		standalone)
			{ command_is_exists 'ping' && command_is_exists 'ping6'; } && { ping4='ping'; ping6='ping6'; } || log_error "command not found: ping/ping6"
			;;
		parameter)
			command_is_exists 'ping' && { ping4='ping -4'; ping6='ping -6'; } || log_error "command not found: ping"
			;;
		*)
			log_error "the value of the opts_ping_cmd_to_use option is invalid: $opts_ping_cmd_to_use"
			;;
	esac

	case "$opts_hostname_resolver" in
		auto)
			if command_is_exists 'nslookup' || command_is_exists 'wget' || command_is_exists 'curl' ; then
				resolver_func='resolve_hostname_by_doh'
			elif command_is_exists 'dig'; then
				resolver_func='resolve_hostname_by_dig'
			elif command_is_exists 'getent'; then
				resolver_func='resolve_hostname_by_getent'
			elif command_is_exists 'ping'; then
				resolver_func='resolve_hostname_by_ping'
			else
				log_error "command not found: nslookup/wget/curl/dig/getent/ping"
			fi
			;;
		doh)
			if command_is_exists 'nslookup' || command_is_exists 'wget' || command_is_exists 'curl' ; then
				resolver_func='resolve_hostname_by_doh'
			else
				log_error "command not found: nslookup/wget/curl"
			fi
			;;
		dig)
			command_is_exists 'dig' && resolver_func='resolve_hostname_by_dig' || log_error "command not found: dig"
			;;
		getent)
			command_is_exists 'getent' && resolver_func='resolve_hostname_by_getent' || log_error "command not found: getent"
			;;
		ping)
			command_is_exists 'ping' && resolver_func='resolve_hostname_by_ping' || log_error "command not found: ping"
			;;
		*)
			log_error "the value of the opts_hostname_resolver option is invalid: $opts_hostname_resolver"
			;;
	esac
}

gfwlist_txt_append_domain_names() {
	printf "cn2qq.com\ngithub.io\ngithub.com\nrawgit.com\nrawgithub.com\ngithubusercontent.com\ngoogleapis.cn\ngoogleapis.com\n"
	printf "twimg.edgesuite.net\nv2fly.org\nv2ray.com\n"
	printf "blogspot.ae\nblogspot.al\nblogspot.am\nblogspot.ba\nblogspot.be\nblogspot.bg\nblogspot.bj\nblogspot.ca\nblogspot.cat\nblogspot.cf\nblogspot.ch\nblogspot.cl\nblogspot.co.at\nblogspot.co.id\nblogspot.co.il\nblogspot.co.ke\nblogspot.com\nblogspot.com.ar\nblogspot.com.au\nblogspot.com.br\nblogspot.com.by\nblogspot.com.co\nblogspot.com.cy\nblogspot.com.ee\nblogspot.com.eg\nblogspot.com.es\nblogspot.com.mt\nblogspot.com.ng\nblogspot.com.tr\nblogspot.com.uy\nblogspot.co.nz\nblogspot.co.uk\nblogspot.co.za\nblogspot.cv\nblogspot.cz\nblogspot.de\nblogspot.dk\nblogspot.fi\nblogspot.fr\nblogspot.gr\nblogspot.hk\nblogspot.hr\nblogspot.hu\nblogspot.ie\nblogspot.in\nblogspot.is\nblogspot.it\nblogspot.jp\nblogspot.kr\nblogspot.li\nblogspot.lt\nblogspot.lu\nblogspot.md\nblogspot.mk\nblogspot.mr\nblogspot.mx\nblogspot.my\nblogspot.nl\nblogspot.no\nblogspot.pe\nblogspot.pt\nblogspot.qa\nblogspot.re\nblogspot.ro\nblogspot.rs\nblogspot.ru\nblogspot.se\nblogspot.sg\nblogspot.si\nblogspot.sk\nblogspot.sn\nblogspot.td\nblogspot.tw\nblogspot.ug\nblogspot.vn\n"
	printf "google.ac\ngoogle.ad\ngoogle.ae\ngoogle.al\ngoogle.am\ngoogle.as\ngoogle.at\ngoogle.az\ngoogle.ba\ngoogle.be\ngoogle.bf\ngoogle.bg\ngoogle.bi\ngoogle.bj\ngoogle.bs\ngoogle.bt\ngoogle.by\ngoogle.ca\ngoogle.cat\ngoogle.cc\ngoogle.cd\ngoogle.cf\ngoogle.cg\ngoogle.ch\ngoogle.ci\ngoogle.cl\ngoogle.cm\ngoogle.cn\ngoogle.co.ao\ngoogle.co.bw\ngoogle.co.ck\ngoogle.co.cr\ngoogle.co.id\ngoogle.co.il\ngoogle.co.in\ngoogle.co.jp\ngoogle.co.ke\ngoogle.co.kr\ngoogle.co.ls\ngoogle.com\ngoogle.co.ma\ngoogle.com.af\ngoogle.com.ag\ngoogle.com.ai\ngoogle.com.ar\ngoogle.com.au\ngoogle.com.bd\ngoogle.com.bh\ngoogle.com.bn\ngoogle.com.bo\ngoogle.com.br\ngoogle.com.bz\ngoogle.com.co\ngoogle.com.cu\ngoogle.com.cy\ngoogle.com.do\ngoogle.com.ec\ngoogle.com.eg\ngoogle.com.et\ngoogle.com.fj\ngoogle.com.gh\ngoogle.com.gi\ngoogle.com.gt\ngoogle.com.hk\ngoogle.com.jm\ngoogle.com.kh\ngoogle.com.kw\ngoogle.com.lb\ngoogle.com.lc\ngoogle.com.ly\ngoogle.com.mm\ngoogle.com.mt\ngoogle.com.mx\ngoogle.com.my\ngoogle.com.na\ngoogle.com.nf\ngoogle.com.ng\ngoogle.com.ni\ngoogle.com.np\ngoogle.com.om\ngoogle.com.pa\ngoogle.com.pe\ngoogle.com.pg\ngoogle.com.ph\ngoogle.com.pk\ngoogle.com.pr\ngoogle.com.py\ngoogle.com.qa\ngoogle.com.sa\ngoogle.com.sb\ngoogle.com.sg\ngoogle.com.sl\ngoogle.com.sv\ngoogle.com.tj\ngoogle.com.tr\ngoogle.com.tw\ngoogle.com.ua\ngoogle.com.uy\ngoogle.com.vc\ngoogle.com.vn\ngoogle.co.mz\ngoogle.co.nz\ngoogle.co.th\ngoogle.co.tz\ngoogle.co.ug\ngoogle.co.uk\ngoogle.co.uz\ngoogle.co.ve\ngoogle.co.vi\ngoogle.co.za\ngoogle.co.zm\ngoogle.co.zw\ngoogle.cv\ngoogle.cz\ngoogle.de\ngoogle.dj\ngoogle.dk\ngoogle.dm\ngoogle.dz\ngoogle.ee\ngoogle.es\ngoogle.fi\ngoogle.fm\ngoogle.fr\ngoogle.ga\ngoogle.ge\ngoogle.gf\ngoogle.gg\ngoogle.gl\ngoogle.gm\ngoogle.gp\ngoogle.gr\ngoogle.gy\ngoogle.hn\ngoogle.hr\ngoogle.ht\ngoogle.hu\ngoogle.ie\ngoogle.im\ngoogle.io\ngoogle.iq\ngoogle.is\ngoogle.it\ngoogle.je\ngoogle.jo\ngoogle.kg\ngoogle.ki\ngoogle.kz\ngoogle.la\ngoogle.li\ngoogle.lk\ngoogle.lt\ngoogle.lu\ngoogle.lv\ngoogle.md\ngoogle.me\ngoogle.mg\ngoogle.mk\ngoogle.ml\ngoogle.mn\ngoogle.ms\ngoogle.mu\ngoogle.mv\ngoogle.mw\ngoogle.ne\ngoogle.net\ngoogle.nl\ngoogle.no\ngoogle.nr\ngoogle.nu\ngoogle.org\ngoogle.pl\ngoogle.pn\ngoogle.ps\ngoogle.pt\ngoogle.ro\ngoogle.rs\ngoogle.ru\ngoogle.rw\ngoogle.sc\ngoogle.se\ngoogle.sh\ngoogle.si\ngoogle.sk\ngoogle.sm\ngoogle.sn\ngoogle.so\ngoogle.sr\ngoogle.st\ngoogle.td\ngoogle.tg\ngoogle.tk\ngoogle.tl\ngoogle.tm\ngoogle.tn\ngoogle.to\ngoogle.tt\ngoogle.vg\ngoogle.vu\ngoogle.ws\n"
}

update_gfwlist() {
	update_gfwlist_file
	update_gfwlist_ipset
	return
}

update_gfwlist_file() {
	logger -t "【update_gfwlist】" "开始下载更新 gfwlist 文件...."
	mkdir -p /opt/app/ss_tproxy/rule
	tmp_base64_gfwlist="/opt/app/ss_tproxy/rule/tmp_base64_gfwlist.txt"
	tmp_gfwlist="/opt/app/ss_tproxy/rule/tmp_gfwlist.txt"
	tmp_down_file="/opt/app/ss_tproxy/rule/tmp_gfwlist_tmp.txt"
	rm -f $tmp_gfwlist $tmp_down_file $tmp_base64_gfwlist
	echo "" > /opt/app/ss_tproxy/rule/gfwlist_dns.txt
	echo "" > /opt/app/ss_tproxy/rule/gfwlist_ip.txt
	echo "" > /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt
	ss_3p_enable=`nvram get ss_3p_enable`
	if [ "$ss_3p_enable" = "1" ] ; then
	ss_3p_gfwlist=`nvram get ss_3p_gfwlist`
	if [ "$ss_3p_gfwlist" = "1" ] ; then
		logger -t "【update_gfwlist】" "正在获取官方 gfwlist...."
		url='https://gcore.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt'
		raw_url='https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt'
		wgetcurl_checkmd5 $tmp_base64_gfwlist  "$url" "$raw_url" N 5
		if [ -s $tmp_base64_gfwlist ] && [ -z "$(cat $tmp_base64_gfwlist | grep -Eo [^A-Za-z0-9+/=]+ | tr -d "\n")" ] ; then
		dos2unix $tmp_base64_gfwlist
		sed -e  ':a;N;$!ba;s/\n//g' -i $tmp_base64_gfwlist
		sed -e  's@$@====@g' -i $tmp_base64_gfwlist
		cat $tmp_base64_gfwlist | base64 -d > $tmp_down_file
		rm -f $tmp_base64_gfwlist 
		[ -z "$(cat $tmp_down_file | grep google )" ] && { rm -f $tmp_down_file ; logger -t "【update_gfwlist】" "错误！！！找不到 google ，base64 解码官方 gfwlist 数据不完整" ; }
		[ -z "$(cat $tmp_down_file | grep '\-\-\-EOF\-\-\-' )" ] && { rm -f $tmp_down_file ; logger -t "【update_gfwlist】" "错误！！！ 找不到 EOF ， base64 解码官方 gfwlist 数据不完整" ; }
		if [ -s $tmp_down_file ] ; then
		# blacklist
		cat $tmp_down_file | sort -u |
			sed '/^$\|@@/d'|
			sed 's#!.\+##; s#|##g; s#@##g; s#http:\/\/##; s#https:\/\/##;' | 
			sed '/\*/d; /apple\.com/d; /sina\.cn/d; /sina\.com\.cn/d; /baidu\.com/d; /byr\.cn/d; /weibo\.com/d; /zhongsou\.com/d; /youdao\.com/d; /sogou\.com/d; /so\.com/d; /soso\.com/d; /aliyun\.com/d; /taobao\.com/d; /jd\.com/d; /qq\.com/d; /iqiyi\.com/d;' |
			sed '/^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/d' |
			grep '^[0-9a-zA-Z\.-]\+$' | grep '\.' | sed 's#^\.\+##' | sed 's/^[[:space:]]*//g; /^$/d; /#/d; s/comUSA/com/g;' | sort -u >> $tmp_gfwlist
		# whitelist
		cat $tmp_down_file | sort -u |
			sed '/^$/d'| grep '^@@.\+$' |
			sed 's#@##g; s#|##g; s#http:\/\/##; s#https:\/\/##;' |
			sed '/^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/d' |
			grep '^[0-9a-zA-Z\.-]\+$' | grep '\.' | sed 's#^\.\+##' | sed 's/^[[:space:]]*//g; /^$/d; /#/d; s/comUSA/com/g;' | sort -u | sed '/^$/d' >> /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt
			printf "sina.cn\nsina.com.cn\nbaidu.com\nbyr.cn\n\nweibo.com\nzhongsou.com\nyoudao.com\nsogou.com\nso.com\nsoso.com\naliyun.com\ntaobao.com\njd.com\nqq.com\niqiyi.com\ngoogle.cn\n" >> /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt
			sed -e '/^$/d' -i /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt
		fi
		else
		logger -t "【update_gfwlist】" "错误！！！获取官方 gfwlist 下载失败"
		fi
		rm -f $tmp_down_file
	fi
	ss_3p_kool=`nvram get ss_3p_kool`
	if [ "$ss_3p_kool" = "1" ] ; then
		logger -t "【update_gfwlist】" "正在获取 koolshare 列表...."
		url='https://gcore.jsdelivr.net/gh/hq450/fancyss/rules/gfwlist.conf'
		raw_url='https://raw.githubusercontent.com/hq450/fancyss/master/rules/gfwlist.conf'
		wgetcurl_checkmd5 $tmp_down_file "$url" "$raw_url" N 5
		if [ -s $tmp_down_file ] ; then
		echo ""  >> $tmp_down_file
		cat $tmp_down_file | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | sed 's/ipset=\/\.//g; s/\/gfwlist//g; /^server/d' >> $tmp_gfwlist
		fi
		rm -f $tmp_down_file
	fi
	ss_sub5=`nvram get ss_sub5`
	if [ ! -z "$ss_sub5" ] ; then
		logger -t "【update_gfwlist】" "正在获取 GFW 自定义域名 列表...."
		wgetcurl_checkmd5 $tmp_down_file $ss_sub5 $ss_sub5 Y
		if [ -s $tmp_down_file ] && [ ! -z "$(cat $tmp_down_file | grep -Eo [^A-Za-z0-9+/=]+ | tr -d "\n")" ] ; then
		echo ""  >> $tmp_down_file
		cat $tmp_down_file | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | sed 's/ipset=\/\.//g; s/\/gfwlist//g; /^server/d' | sort -u | grep -v '^$' >> $tmp_gfwlist
		else
		logger -t "【update_chnroute】" "错误！！！获取 GFW 自定义域名 列表 下载失败"
		fi
		rm -f $tmp_down_file
	fi
	if [ ! -s $tmp_gfwlist ] ; then
		logger -t "【update_gfwlist】" "加入 固件内置list规则 列表...."
		rm -f /etc/storage/basedomain.txt
		tar -xzvf /etc_ro/basedomain.tgz -C /tmp ; cd /opt
		ln -sf /tmp/basedomain.txt /etc/storage/basedomain.txt
		[ -s /etc/storage/basedomain.txt ] && cat /etc/storage/basedomain.txt | sort -u >> $tmp_gfwlist
	fi
	ss_sub1=`nvram get ss_sub1`
	if [ "$ss_sub1" = "1" ] ; then
		logger -t "【update_gfwlist】" "处理订阅列表1....海外加速"
		url='/list.txt'
		wgetcurl_checkmd5 $tmp_down_file "$hiboyfile$url" "$hiboyfile2$url" N 5
		if [ -s $tmp_down_file ] ; then
		echo ""  >> $tmp_down_file
		cat $tmp_down_file | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | sed 's/ipset=\/\.//g; s/\/gfwlist//g; /^server/d' >> $tmp_gfwlist
		fi
		rm -f $tmp_down_file
	fi
	ss_sub2=`nvram get ss_sub2`
	if [ "$ss_sub2" = "1" ] ; then
		#处理只做dns解释的域名
		logger -t "【update_gfwlist】" "处理订阅列表2....处理只做dns解释的域名"
		url='/dnsonly.txt'
		wgetcurl_checkmd5 $tmp_down_file "$hiboyfile$url" "$hiboyfile2$url" N 5
		if [ -s $tmp_down_file ] ; then
		echo ""  >> $tmp_down_file
		cat $tmp_down_file | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | sed 's/ipset=\/\.//g; s/\/gfwlist//g; /^server/d' > /opt/app/ss_tproxy/rule/gfwlist_dns.txt
		fi
		rm -f $tmp_down_file
	fi
	ss_sub3=`nvram get ss_sub3`
	if [ "$ss_sub3" = "1" ] ; then
		#处理需要排除的域名解释
		logger -t "【update_gfwlist】" "处理订阅列表3....处理需要排除的域名解释"
		url='/passby.txt'
		wgetcurl_checkmd5 $tmp_down_file "$hiboyfile$url" "$hiboyfile2$url" N 5
		if [ -s $tmp_down_file ] ; then
		echo ""  >> $tmp_down_file
		cat $tmp_down_file | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | sed 's/ipset=\/\.//g; s/\/gfwlist//g; /^server/d' >> /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt
		fi
		rm -f $tmp_down_file
	fi
	ss_sub6=`nvram get ss_sub6`
	if [ ! -z "$ss_sub6" ] ; then
		logger -t "【update_gfwlist】" "正在获取 GFW IP 列表...."
		wgetcurl_checkmd5 $tmp_down_file $ss_sub6 $ss_sub6 Y
		if [ -s $tmp_down_file ] && [ ! -z "$(cat $tmp_down_file | grep -Eo [^A-Za-z0-9+/=]+ | tr -d "\n")" ] ; then
		echo ""  >> $tmp_down_file
		cat $tmp_down_file | grep -v '^#' | sort -u | grep -v '^$' | grep -E -o '([0-9]+\.){3}[0-9/]+' > /opt/app/ss_tproxy/rule/gfwlist_ip.txt
		else
		logger -t "【update_chnroute】" "错误！！！获取 GFW IP 列表 下载失败"
		fi
		rm -f $tmp_down_file
	fi
	fi
	if [ ! -s $tmp_gfwlist ] ; then
		logger -t "【update_gfwlist】" "加入 固件内置list规则 列表...."
		rm -f /etc/storage/basedomain.txt
		tar -xzvf /etc_ro/basedomain.tgz -C /tmp ; cd /opt
		ln -sf /tmp/basedomain.txt /etc/storage/basedomain.txt
		[ -s /etc/storage/basedomain.txt ] && cat /etc/storage/basedomain.txt | sort -u >> $tmp_gfwlist
	fi
	rm -f $tmp_down_file
	# 临时添加的域名
	echo "whatsapp.net" >> $tmp_gfwlist
	gfwlist_txt_append_domain_names >> $tmp_gfwlist
	# 添加自定义黑名单
	cat $file_wanlist_ext | grep -E "^@g" | cut -c4- | while read domain_addr; do echo "$domain_addr" >> $tmp_gfwlist; done 
	#删除忽略的域名
	cat $file_wanlist_ext | grep -E "^@b" | cut -c4- > /opt/app/ss_tproxy/tmp/awk_del_list_tmp
	awk_del_list /opt/app/ss_tproxy/tmp/awk_del_list_tmp $tmp_gfwlist
	cat /etc/storage/shadowsocks_mydomain_script.sh | sed '/^$\|#/d' | sed "s/http://g" | sed "s/https://g" | sed "s/\///g" | sort -u >> $tmp_gfwlist
	cat $tmp_gfwlist |grep -v '^#' | sort -u | grep -v '^$' > $file_gfwlist_txt
	sed -e '/^$/d' -i $file_gfwlist_txt
	dos2unix $file_gfwlist_txt
	logger -t "【update_gfwlist】" "完成下载 gfwlist 文件"
	rm -f $tmp_gfwlist
	rm -f /etc/storage/basedomain.txt
	ln -sf $file_gfwlist_txt /etc/storage/basedomain.txt
}

update_md5_check() {
    md5_file=/opt/app/ss_tproxy/tmp/$1.md5
    shift
    md5_check="NOT"
    # 检测配置文件变化，不匹配则进行更新ipset
    if [ ! -s "$md5_file" ] ; then
        md5sum "$@" $ss_tproxy_config /opt/app/ss_tproxy/ss_tproxy > $md5_file
        return 1
    fi
    md5sum -s -c $md5_file
    if [ "$?" == "0" ] ; then
        md5_check="OK"
        return 0
    else
        md5sum "$@" $ss_tproxy_config /opt/app/ss_tproxy/ss_tproxy > $md5_file
        md5_check="NOT"
        return 1
    fi
}
update_cflist_ipset() {
a_ipset_conf=$1
b_ipset_conf=$2
# [a =>> b] 重复的 ipset 规则合并
# 把 a 文件 [ipset=/opt.cn2qq.com/adbybylist]
# 合并到已存在的 b 文件 [ipset=/opt.cn2qq.com/gfwlist]
# 得到 b 文件 [ipset=/opt.cn2qq.com/gfwlist,adbybylist]
if [ -s $a_ipset_conf ] ; then

echo "$(awk -F '/' '\
NR==FNR{\
  alist=$3
  if($1 == "ipset=") {\
    a[$2]++\
  }\
}\
NR>FNR{\
  if($1 == "ipset=") {\
    if($2 in a) {\
      if($0 ~ alist) {\
        print $0}\
      else{\
        print $0","alist}\
      }\
    else{\
      print $0}\
  }\
  else{\
    print $0
  }\
}' $a_ipset_conf $b_ipset_conf)" > $b_ipset_conf

echo "$(awk -F '/' '\
NR==FNR{\
  if($1 == "ipset=") {\
    a[$2]++\
  }\
}\
NR>FNR{\
  if($1 == "ipset=") {\
    if(!($2 in a)) {\
      print $0}\
  }\
  else{\
    print $0
  }\
}' $b_ipset_conf $a_ipset_conf)" >> $b_ipset_conf

fi
}
update_gfwlist_ipset() {
	mkdir -p /opt/app/ss_tproxy/dnsmasq.d
	touch /opt/app/ss_tproxy/rule/gfwlist_ip.txt /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt /opt/app/ss_tproxy/rule/gfwlist_dns.txt
	update_md5_check update_gfwlist_dns /opt/app/ss_tproxy/rule/gfwlist_dns.txt /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt
	if is_md5_not ; then
		echo "" > /opt/app/ss_tproxy/dnsmasq.d/r.sub.conf
		if [ -s /opt/app/ss_tproxy/rule/gfwlist_dns.txt ] ; then
		is_true "$ipv4" && cat /opt/app/ss_tproxy/rule/gfwlist_dns.txt | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | awk '{printf("server=/%s/'"$dns4_fw_type"'\n", $1)}' >> /opt/app/ss_tproxy/dnsmasq.d/r.sub.conf
		is_true "$ipv6" && cat /opt/app/ss_tproxy/rule/gfwlist_dns.txt | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | awk '{printf("server=/%s/'"$dns6_fw_type"'\n", $1)}' >> /opt/app/ss_tproxy/dnsmasq.d/r.sub.conf
		fi
		if [ -s /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt ] ; then
		wan_dnsenable_x="$(nvram get wan_dnsenable_x)"
		[ "$wan_dnsenable_x" == "1" ] && DNS_china=`nvram get wan0_dns |cut -d ' ' -f1`
		[ "$wan_dnsenable_x" != "1" ] && DNS_china=`nvram get wan_dns1_x |cut -d ' ' -f1`
		[ -z "$DNS_china" ] && DNS_china="$dns_direct"
		is_true "$ipv4" && cat /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | awk '{printf("server=/%s/'"$DNS_china"'\n", $1)}' >> /opt/app/ss_tproxy/dnsmasq.d/r.sub.conf
		is_true "$ipv6" && cat /opt/app/ss_tproxy/rule/gfwlist_dns_b.txt | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | awk '{printf("server=/%s/'"$dns_direct6"'\n", $1)}' >> /opt/app/ss_tproxy/dnsmasq.d/r.sub.conf
		fi
	fi
	if [ ! -s $file_gfwlist_txt ] ; then
		logger -t "【update_gfwlist】" "错误！！！$file_gfwlist_txt 文件为空，使用 固件内置 /etc/storage/basedomain.txt 规则...."
		rm -f /etc/storage/basedomain.txt
		tar -xzvf /etc_ro/basedomain.tgz -C /tmp ; cd /opt
		ln -sf /tmp/basedomain.txt /etc/storage/basedomain.txt
		[ -s /etc/storage/basedomain.txt ] && cat /etc/storage/basedomain.txt | sort -u >> $file_gfwlist_txt
		gfwlist_txt_append_domain_names >> $file_gfwlist_txt
	fi
	sed -e '/^$/d' -i $file_gfwlist_txt
	if ! is_chnlist_mode; then
	update_md5_check update_gfwlist_txt $file_gfwlist_txt
	logger -t "【update_gfwlist】" "开始加载 gfwlist 规则...."
	if is_md5_not ; then
	echo "" > /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
	if [ -s $file_gfwlist_txt ] ; then
		# 开始构造dnsmasq.conf
		if is_true "$ipv4" && is_true "$ipv6"; then
			gfwlist_ipset_setname="gfwlist,gfwlist6"
			ipset -! create gfwlist hash:net family inet
			ipset flush gfwlist &>/dev/null
			ipset -! create gfwlist6 hash:net family inet6
			ipset flush gfwlist6 &>/dev/null
		elif is_true "$ipv4"; then
			gfwlist_ipset_setname="gfwlist"
			ipset -! create gfwlist hash:net family inet
			ipset flush gfwlist &>/dev/null
		else
			gfwlist_ipset_setname="gfwlist6"
			ipset -! create gfwlist6 hash:net family inet6
			ipset flush gfwlist6 &>/dev/null
		fi
		gfwlist_conf=""
		export file_number=`wc -l $file_gfwlist_txt | awk -F'\ ' '{print $1}'`
		is_true "$ipv4" && logger -t "【update_gfwlist】" "已经加载 gfwlist dns ipv4 规则 0%" && gfwlist_conf="$(awk 'BEGIN {c=0;a=1}{printf("server=/%s/127.0.0.1#8053\n", $1 )}{i++}{b=i/ENVIRON["file_number"]*10}{if(b>a){a++}}{if(c!=a){c=a;system("eval  sed \\\"s/已经加载 gfwlist dns ipv4 规则.+/已经加载 gfwlist dns ipv4 规则 "c"0%/g\\\"  -Ei /tmp/syslog.log")}}' $file_gfwlist_txt)" && echo "$gfwlist_conf" >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		gfwlist_conf=""
		is_true "$ipv6" && logger -t "【update_gfwlist】" "已经加载 gfwlist dns ipv6 规则 0%" && gfwlist_conf="$(awk 'BEGIN {c=0;a=1}{printf("server=/%s/'"$dns_remote6"'\n", $1 )}{i++}{b=i/ENVIRON["file_number"]*10}{if(b>a){a++}}{if(c!=a){c=a;system("eval  sed \\\"s/已经加载 gfwlist dns ipv6 规则.+/已经加载 gfwlist dns ipv6 规则 "c"0%/g\\\"  -Ei /tmp/syslog.log")}}' $file_gfwlist_txt)" && echo "$gfwlist_conf" >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		gfwlist_conf=""
		logger -t "【update_gfwlist】" "已经加载 gfwlist ipset 规则 0%" && gfwlist_conf="$(awk 'BEGIN {c=0;a=1}{printf("ipset=/%s/'"$gfwlist_ipset_setname"'\n", $1 )}{i++}{b=i/ENVIRON["file_number"]*10}{if(b>a){a++}}{if(c!=a){c=a;system("eval  sed \\\"s/已经加载 gfwlist ipset 规则.+/已经加载 gfwlist ipset 规则 "c"0%/g\\\"  -Ei /tmp/syslog.log")}}' $file_gfwlist_txt)" && echo "$gfwlist_conf" >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		gfwlist_conf=""
		sed -e '/^$/d' -i /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		nvram set gfwlist_list="gfwlist规则`cat /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf | wc -l` 行 Update:$(date "+%m-%d %H:%M")"
		logger -t "【update_gfwlist】" "配置更新，完成加载 gfwlist 规则...."
	else
		logger -t "【update_gfwlist】" "更新错误！！！ $file_gfwlist_txt 规则为空...."
	fi
	else
		[ ! -s $file_gfwlist_txt ] && logger -t "【update_gfwlist】" "匹配错误！！！ $file_gfwlist_txt 规则为空...."
		logger -t "【update_gfwlist】" "配置匹配，完成加载 gfwlist 规则...."
	fi
	fi
}

update_chnlist() {
	update_chnlist_file
	[ "$ss_pdnsd_cn_all" != "1" ] && update_chnlist_file "chnlist_mini.txt"
	return
}

update_chnlist_file() {
	logger -t "【update_chnlist】" "开始下载更新 chnlist 文件...."
	mkdir -p /opt/app/ss_tproxy/rule
	tmp_down_file="/opt/app/ss_tproxy/rule/tmp_chnlist_tmp.txt"
	rm -f $tmp_down_file
	#url='https://gcore.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf'
	#raw_url='https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/accelerated-domains.china.conf'
	#wgetcurl_checkmd5 $tmp_down_file "$url" "$raw_url" N 5
	if [ "$1" = 'chnlist_mini.txt' ] ; then
	chnlist_txt="chnlist_mini.txt"
	wgetcurl_checkmd5 $tmp_down_file "$hiboyfile/chinalist.txt" "$hiboyfile2/chinalist.txt" N 5
	else
	chnlist_txt="chnlist.txt"
	wgetcurl_checkmd5 $tmp_down_file "$hiboyfile/accelerated-domains.china.conf" "$hiboyfile2/accelerated-domains.china.conf" N 5
	fi
	sed -e "s@server=/@@g" -i  $tmp_down_file
	sed -e 's@/.*@@g' -i  $tmp_down_file
	printf "com.cn\nedu.cn\nnet.cn\norg.cn\ngov.cn\n" >> $tmp_down_file
	# 添加自定义白名单
	cat $file_wanlist_ext | grep -E "^@b" | cut -c4- | while read domain_addr; do echo "$domain_addr" >> $tmp_down_file; done 
	#删除忽略的域名
	cat $file_wanlist_ext | grep -E "^@g" | cut -c4- > /opt/app/ss_tproxy/tmp/awk_del_list_tmp
	awk_del_list /opt/app/ss_tproxy/tmp/awk_del_list_tmp $tmp_down_file
	cat $tmp_down_file | grep -v '^#' | sort -u | grep -v '^$' > /opt/app/ss_tproxy/rule/$chnlist_txt
	sed -e '/^$/d' -i /opt/app/ss_tproxy/rule/$chnlist_txt
	#删除gfwlist的域名
	awk_del_list $file_gfwlist_txt /opt/app/ss_tproxy/rule/$chnlist_txt
	dos2unix /opt/app/ss_tproxy/rule/$chnlist_txt
	logger -t "【update_chnlist】" "完成下载 $chnlist_txt 文件"
	rm -f $tmp_down_file
}

update_chnlist_ipset() {
	mkdir -p /opt/app/ss_tproxy/dnsmasq.d
	sed -e '/^$/d' -i /opt/app/ss_tproxy/rule/chnlist.txt
	if is_chnlist_mode; then
		[ ! -s /opt/app/ss_tproxy/rule/chnlist.txt ] && update_chnlist_file
		logger -t "【update_chnlist】" "开始加载 chnlist 规则（回国模式）...."
		update_md5_check update_chnlist1_txt /opt/app/ss_tproxy/rule/chnlist.txt
		if is_md5_not ; then
		echo "" > /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		echo "" > /opt/app/ss_tproxy/dnsmasq.d/accelerated-domains.china.conf
		if [ -s /opt/app/ss_tproxy/rule/chnlist.txt ] ; then
		# 开始构造dnsmasq.conf
		if is_true "$ipv4" && is_true "$ipv6"; then
			gfwlist_ipset_setname="gfwlist,gfwlist6"
			ipset -! create gfwlist hash:net family inet
			ipset flush gfwlist &>/dev/null
			ipset -! create gfwlist6 hash:net family inet6
			ipset flush gfwlist6 &>/dev/null
		elif is_true "$ipv4"; then
			gfwlist_ipset_setname="gfwlist"
			ipset -! create gfwlist hash:net family inet
			ipset flush gfwlist &>/dev/null
		else
			gfwlist_ipset_setname="gfwlist6"
			ipset -! create gfwlist6 hash:net family inet6
			ipset flush gfwlist6 &>/dev/null
		fi
		# 回国模式直接使用远端DNS走代理，停止使用 dnsproxy
		chnlist_conf=""
		export file_number=`wc -l /opt/app/ss_tproxy/rule/chnlist.txt | awk -F'\ ' '{print $1}'`
		is_true "$ipv4" && logger -t "【update_chnlist】" "已经加载 chnlist dns ipv4 规则 0%" && chnlist_conf="$(awk 'BEGIN {c=0;a=1}{printf("server=/%s/'"$dns_remote"'\n", $1 )}{i++}{b=i/ENVIRON["file_number"]*10}{if(b>a){a++}}{if(c!=a){c=a;system("eval  sed \\\"s/已经加载 chnlist dns ipv4 规则.+/已经加载 chnlist dns ipv4 规则 "c"0%/g\\\"  -Ei /tmp/syslog.log")}}' /opt/app/ss_tproxy/rule/chnlist.txt)" && echo "$chnlist_conf" >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		chnlist_conf=""
		is_true "$ipv6" && logger -t "【update_chnlist】" "已经加载 chnlist dns ipv6 规则 0%" && chnlist_conf="$(awk 'BEGIN {c=0;a=1}{printf("server=/%s/'"$dns_remote6"'\n", $1 )}{i++}{b=i/ENVIRON["file_number"]*10}{if(b>a){a++}}{if(c!=a){c=a;system("eval  sed \\\"s/已经加载 chnlist dns ipv6 规则.+/已经加载 chnlist dns ipv6 规则 "c"0%/g\\\"  -Ei /tmp/syslog.log")}}' /opt/app/ss_tproxy/rule/chnlist.txt)" && echo "$chnlist_conf" >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		chnlist_conf=""
		logger -t "【update_chnlist】" "已经加载 chnlist ipset 规则 0%" && chnlist_conf="$(awk 'BEGIN {c=0;a=1}{printf("ipset=/%s/'"$gfwlist_ipset_setname"'\n", $1 )}{i++}{b=i/ENVIRON["file_number"]*10}{if(b>a){a++}}{if(c!=a){c=a;system("eval  sed \\\"s/已经加载 chnlist ipset 规则.+/已经加载 chnlist ipset 规则 "c"0%/g\\\"  -Ei /tmp/syslog.log")}}' /opt/app/ss_tproxy/rule/chnlist.txt)" && echo "$chnlist_conf" >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		chnlist_conf=""
		sed -e '/^$/d' -i /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		logger -t "【update_chnlist】" "配置更新，完成加载 chnlist 规则...."
		else
		logger -t "【update_chnlist】" "更新错误！！！ /opt/app/ss_tproxy/rule/chnlist.txt 规则为空...."
		fi
		else
			[ ! -s /opt/app/ss_tproxy/rule/chnlist.txt ] && logger -t "【update_chnlist】" "匹配错误！！！ /opt/app/ss_tproxy/rule/chnlist.txt 规则为空...."
			logger -t "【update_chnlist】" "配置匹配，完成加载 chnlist 规则...."
		fi
	else
		if [ "$ss_pdnsd_cn_all" != "1" ] ; then
		[ ! -s /opt/app/ss_tproxy/rule/chnlist_mini.txt ] && update_chnlist_file "chnlist_mini.txt"
		update_md5_check update_chnlist2_txt /opt/app/ss_tproxy/rule/chnlist_mini.txt
		if is_md5_not ; then
		echo "" > /opt/app/ss_tproxy/dnsmasq.d/accelerated-domains.china.conf
		if [ -s /opt/app/ss_tproxy/rule/chnlist_mini.txt ] ; then
		logger -t "【update_chnlist_mini】" "加速国内 dns 访问"
		logger -t "【update_chnlist_mini】" "开始加载 chnlist_mini 规则...."
		wan_dnsenable_x="$(nvram get wan_dnsenable_x)"
		[ "$wan_dnsenable_x" == "1" ] && DNS_china=`nvram get wan0_dns |cut -d ' ' -f1`
		[ "$wan_dnsenable_x" != "1" ] && DNS_china=`nvram get wan_dns1_x |cut -d ' ' -f1`
		[ -z "$DNS_china" ] && DNS_china="$dns_direct"
		chnlist_conf=""
		export file_number=`cat /opt/app/ss_tproxy/rule/chnlist_mini.txt | sed -e 's@^cn$@com.cn@g' |sed 's/^[[:space:]]*//g; /^$/d; /#/d' |wc -l|awk -F'\ ' '{print $1}'`
		is_true "$ipv4" && logger -t "【update_chnlist_mini】" "已经加载 chnlist_mini ipv4 规则 0%" && chnlist_conf="$(cat /opt/app/ss_tproxy/rule/chnlist_mini.txt | sed -e 's@^cn$@com.cn@g' | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | awk 'BEGIN {c=0;a=1}{printf("server=/%s/'"$DNS_china"'\n", $1)}{i++}{b=i/ENVIRON["file_number"]*10}{if(b>a){a++}}{if(c!=a){c=a;system("eval  sed \\\"s/已经加载 chnlist_mini ipv4 规则.+/已经加载 chnlist_mini ipv4 规则 "c"0%/g\\\"  -Ei /tmp/syslog.log")}}')" && echo "$chnlist_conf" >> /opt/app/ss_tproxy/dnsmasq.d/accelerated-domains.china.conf
		chnlist_conf=""
		is_true "$ipv6" && logger -t "【update_chnlist_mini】" "已经加载 chnlist_mini ipv6 规则 0%" && chnlist_conf="$(cat /opt/app/ss_tproxy/rule/chnlist_mini.txt | sed -e 's@^cn$@com.cn@g' | sort -u | sed 's/^[[:space:]]*//g; /^$/d; /#/d' | awk 'BEGIN {c=0;a=1}{printf("server=/%s/'"$dns_direct6"'\n", $1)}{i++}{b=i/ENVIRON["file_number"]*10}{if(b>a){a++}}{if(c!=a){c=a;system("eval  sed \\\"s/已经加载 chnlist_mini ipv6 规则.+/已经加载 chnlist_mini ipv6 规则 "c"0%/g\\\"  -Ei /tmp/syslog.log")}}')" && echo "$chnlist_conf" >> /opt/app/ss_tproxy/dnsmasq.d/accelerated-domains.china.conf
		chnlist_conf=""
		logger -t "【update_chnlist_mini】" "配置更新，完成加载 chnlist_mini 规则...."
		sed -e '/^$/d' -i /opt/app/ss_tproxy/dnsmasq.d/accelerated-domains.china.conf
		else
		logger -t "【update_chnlist_mini】" "更新错误！！！ /opt/app/ss_tproxy/rule/chnlist_mini.txt 规则为空...."
		fi
		else
		[ ! -s /opt/app/ss_tproxy/rule/chnlist_mini.txt ] && logger -t "【update_chnlist_mini】" "匹配错误！！！ /opt/app/ss_tproxy/rule/chnlist_mini.txt 规则为空...."
		logger -t "【update_chnlist_mini】" "配置匹配，完成加载 chnlist_mini 规则...."
		fi
		else
		echo "" > /opt/app/ss_tproxy/dnsmasq.d/accelerated-domains.china.conf
		fi
	fi
	nvram set gfwlist_list="gfwlist规则`cat /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf | wc -l` 行 Update:$(date "+%m-%d %H:%M")"

}

update_chnroute() {
	update_chnroute_file
	update_chnroute_ipset
	return
}

update_chnroute6() {
	update_chnroute_file "ipv6"
	update_chnroute_ipset "ipv6"
	return
}

update_chnroute_file() {
	mkdir -p /opt/app/ss_tproxy/rule
	tmp_chnroute="/opt/app/ss_tproxy/rule/tmp_chnroute.txt"
	tmp_down_file="/opt/app/ss_tproxy/rule/tmp_chnroute_tmp.txt"
	rm -f $tmp_chnroute $tmp_down_file
	if [ "$1" != "ipv6" ]; then
	logger -t "【update_chnroute】" "开始下载更新 chnroute 文件...."
	#url='https://gcore.jsdelivr.net/gh/17mon/china_ip_list/china_ip_list.txt'
	#wgetcurl_checkmd5 $tmp_down_file "$url" "$url" N 5
	#if [ -s $tmp_down_file ] ; then
	#echo ""  >> $tmp_down_file
	#cat $tmp_down_file | grep -v '^#' | sort -u | grep -v '^$' >> $tmp_chnroute
	#fi
	#rm -f $tmp_down_file
	wgetcurl_checkmd5 $tmp_down_file "$hiboyfile/chnroute.txt" "$hiboyfile2/chnroute.txt" N 5
	if [ -s $tmp_down_file ] ; then
	echo ""  >> $tmp_down_file
	cat $tmp_down_file | grep -v '^#' | sort -u | grep -v '^$' >> $tmp_chnroute
	fi
	rm -f $tmp_down_file
	ss_sub7=`nvram get ss_sub7`
	if [ ! -z "$ss_sub7" ] ; then
		logger -t "【update_chnroute】" "正在获取 ① 大陆白名单 IP 下载地址...."
		wgetcurl_checkmd5 $tmp_down_file $ss_sub7 $ss_sub7 Y
		if [ -s $tmp_down_file ] && [ ! -z "$(cat $tmp_down_file | grep -Eo [^A-Za-z0-9+/=]+ | tr -d "\n")" ] ; then
		echo ""  >> $tmp_down_file
		cat $tmp_down_file | grep -v '^#' | sort -u | grep -v '^$' >> $tmp_chnroute
		else
		logger -t "【update_chnroute】" "错误！！！获取 ① 大陆白名单 IP 下载失败"
		fi
		rm -f $tmp_down_file
	fi
	ss_sub8=`nvram get ss_sub8`
	if [ ! -z "$ss_sub8" ] ; then
		logger -t "【update_chnroute】" "正在获取 ② 大陆白名单 IP 下载地址...."
		wgetcurl_checkmd5 $tmp_down_file $ss_sub8 $ss_sub8 Y
		if [ -s $tmp_down_file ] && [ ! -z "$(cat $tmp_down_file | grep -Eo [^A-Za-z0-9+/=]+ | tr -d "\n")" ] ; then
		echo ""  >> $tmp_down_file
		cat $tmp_down_file | grep -v '^#' | sort -u | grep -v '^$' >> $tmp_chnroute
		else
		logger -t "【update_chnroute】" "错误！！！获取 ② 大陆白名单 IP 下载失败"
		fi
		rm -f $tmp_down_file
	fi
	rm -f $tmp_down_file
	if [ ! -s $tmp_chnroute ] ; then
		tar -xzvf /etc_ro/china_ip_list.tgz -C /tmp ; cd /opt
		[ -s /tmp/china_ip_list.txt ] && logger -t "【update_chnroute】" "错误！！！下载文件为空，使用 固件内置 /etc_ro/china_ip_list.tgz 规则...." && cat /tmp/china_ip_list.txt > $tmp_chnroute
	fi
	# 添加自定义白名单
	cat $file_wanlist_ext | grep -E "^b" | cut -c3- | while read ip_addr; do echo "$ip_addr" >> $tmp_down_file; done 
	cat $tmp_chnroute | grep -v '^#' | sort -u | grep -v '^$' | grep -E -o '([0-9]+\.){3}[0-9/]+' > $file_chnroute_txt
	rm -f $tmp_chnroute
	rm -f /etc/storage/china_ip_list.txt
	ln -sf $file_chnroute_txt /etc/storage/china_ip_list.txt
	dos2unix $file_chnroute_txt
	logger -t "【update_chnroute】" "完成下载 chnroute 文件"
	fi
	if is_true "$ipv6" || [ "$1" == "ipv6" ]; then
		rm -f $tmp_chnroute $tmp_down_file
		logger -t "【update_chnroute】" "开始下载更新 chnroute6 文件...."
		# wget --user-agent "$user_agent" -O- 'https://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | grep CN | grep ipv6 | awk -F'|' '{printf("%s/%d\n", $4, $5)}' > $tmp_down_file
		url="$hiboyfile/chnroute6.txt"
		wgetcurl_checkmd5 $tmp_down_file "$url" "$url" N 5
		# 添加自定义白名单
		cat $file_wanlist_ext | grep -E "^~b" | cut -c4- | while read ip_addr; do echo "$ip_addr" >> $tmp_down_file; done 
		cat $tmp_down_file | grep -v '^#' | sort -u | grep -v '^$' > $file_chnroute6_txt
		rm -f $tmp_down_file
		dos2unix $file_chnroute6_txt
		logger -t "【update_chnroute】" "完成下载 chnroute6 文件"
	fi
}

update_chnroute_ipset() {
	mkdir -p /opt/app/ss_tproxy/rule
	if [ ! -s $file_chnroute_txt ] ; then
		tar -xzvf /etc_ro/china_ip_list.tgz -C /tmp ; cd /opt
		[ -s /tmp/china_ip_list.txt ] && logger -t "【update_chnroute】" "错误！！！ $file_chnroute_txt 文件为空，使用 固件内置 /etc_ro/china_ip_list.tgz 规则...." && cat /tmp/china_ip_list.txt > $file_chnroute_txt
	fi
	rm -f /etc/storage/china_ip_list.txt
	ln -sf $file_chnroute_txt /etc/storage/china_ip_list.txt
	chnroute_list="chnroute规则`ipset list chnroute -t | awk -F: '/Number/{print $2}'` 行"
	chnroute6_list="chnroute6规则`ipset list chnroute6 -t | awk -F: '/Number/{print $2}'` 行"
	if [ "$1" != "ipv6" ]; then
	logger -t "【update_chnroute】" "开始加载 chnroute 规则...."
	if is_true "$ipv4"; then
	echo "$chnroute_list" > /opt/app/ss_tproxy/tmp/chnroute_list_Number
	update_md5_check update_chnroute_txt $file_chnroute_txt /opt/app/ss_tproxy/tmp/chnroute_list_Number
	if is_md5_not ; then
		if [ -s $file_chnroute_txt ] ; then
		ipset -! create chnroute hash:net family inet
		ipset flush chnroute &>/dev/null
		cat $file_chnroute_txt | grep -v '^#' | sort -u | grep -v '^$' | grep -E -o '([0-9]+\.){3}[0-9/]+' | sed -e "s/^/-A chnroute &/g" | ipset -! restore
		chnroute_list="chnroute规则`ipset list chnroute -t | awk -F: '/Number/{print $2}'` 行"
		nvram set chnroute_list="$chnroute_list Update:$(date "+%m-%d %H:%M")"
		echo "$chnroute_list" > /opt/app/ss_tproxy/tmp/chnroute_list_Number
		update_md5_check update_chnroute_txt $file_chnroute_txt /opt/app/ss_tproxy/tmp/chnroute_list_Number
		logger -t "【update_chnroute】" "配置更新，完成加载 chnroute 规则...."
		else
		logger -t "【update_chnroute】" "更新错误！！！ $file_chnroute_txt 规则为空...."
		fi
	else
		[ ! -s $file_chnroute_txt ] && logger -t "【update_chnroute】" "匹配错误！！！ $file_chnroute_txt 规则为空...."
		logger -t "【update_chnroute】" "配置匹配，完成加载 chnroute 规则...."
	fi
	else
	nvram set chnroute_list="$chnroute_list"
	fi
	fi
	if is_true "$ipv6" || [ "$1" == "ipv6" ]; then
	logger -t "【update_chnroute】" "开始加载 chnroute6 规则...."
	echo "$chnroute6_list" > /opt/app/ss_tproxy/tmp/chnroute6_list_Number
	update_md5_check update_chnroute6_txt $file_chnroute6_txt /opt/app/ss_tproxy/tmp/chnroute6_list_Number
	if is_md5_not ; then
		if [ -s $file_chnroute6_txt ] ; then
		ipset -! create chnroute6 hash:net family inet6
		ipset flush chnroute6 &>/dev/null
		cat $file_chnroute6_txt | grep -v '^#' | sort -u | grep -v '^$' | sed -e "s/^/-A chnroute6 &/g" | ipset -! restore
		chnroute6_list="chnroute6规则`ipset list chnroute6 -t | awk -F: '/Number/{print $2}'` 行"
		nvram set chnroute6_list="$chnroute6_list Update:$(date "+%m-%d %H:%M")"
		echo "$chnroute6_list" > /opt/app/ss_tproxy/tmp/chnroute6_list_Number
		update_md5_check update_chnroute6_txt $file_chnroute6_txt /opt/app/ss_tproxy/tmp/chnroute6_list_Number
		logger -t "【update_chnroute】" "配置更新，完成加载 chnroute6 规则...."
		else
		logger -t "【update_chnroute】" "更新跳过！！！ $file_chnroute6_txt 规则为空...."
		fi
	else
		[ ! -s $file_chnroute6_txt ] && logger -t "【update_chnroute】" "匹配错误！！！ $file_chnroute6_txt 规则为空...."
		logger -t "【update_chnroute】" "配置匹配，完成加载 chnroute6 规则...."
	fi
	else
	nvram set chnroute6_list="$chnroute6_list"
	fi

}

update_wanlanlist_ipset() {

	for setname in $(ipset -n list | grep -i "sstp_"); do
		ipset flush $setname &>/dev/null
		#ipset destroy $setname &>/dev/null
	done

echo "create proxyaddr hash:net hashsize 64 family inet
create proxyaddr6 hash:net hashsize 64 family inet6
create chnroute hash:net hashsize 1024 family inet
create chnroute6 hash:net hashsize 1024 family inet6
create gfwlist hash:net hashsize 1024 family inet
create gfwlist6 hash:net hashsize 1024 family inet6
create adbybylist hash:net hashsize 1024 family inet
create localaddr hash:net hashsize 64 family inet
create localaddr6 hash:net hashsize 64 family inet6
create privaddr hash:net hashsize 64 family inet
create privaddr6 hash:net hashsize 64 family inet6
create sstp_dst_bp hash:net hashsize 64 family inet
create sstp_dst_bp6 hash:net hashsize 64 family inet6
create sstp_dst_fw hash:net hashsize 64 family inet
create sstp_dst_fw6 hash:net hashsize 64 family inet6
create sstp_dst_dns_fw hash:net hashsize 64 family inet
create sstp_dst_dns_fw6 hash:net hashsize 64 family inet6
create sstp_src_ac hash:net hashsize 64 family inet
create sstp_src_ac6 hash:net hashsize 64 family inet6
create sstp_src_bp hash:net hashsize 64 family inet
create sstp_src_bp6 hash:net hashsize 64 family inet6
create sstp_src_fw hash:net hashsize 64 family inet
create sstp_src_fw6 hash:net hashsize 64 family inet6
create sstp_src_gfw hash:net hashsize 64 family inet
create sstp_src_gfw6 hash:net hashsize 64 family inet6
create sstp_src_chn hash:net hashsize 64 family inet
create sstp_src_chn6 hash:net hashsize 64 family inet6
create sstp_mac_ac hash:mac hashsize 64
create sstp_mac_bp hash:mac hashsize 64
create sstp_mac_fw hash:mac hashsize 64
create sstp_mac_gfw hash:mac hashsize 64
create sstp_mac_chn hash:mac hashsize 64" | while read sstp_name; do ipset -! $sstp_name ; done 

	# Telegram IP 规则
	echo "G,8.8.8.8
G,8.8.4.4
G,208.67.222.222
G,208.67.220.220
G,91.108.4.0/22
G,91.108.8.0/22
G,91.108.12.0/22
G,91.108.16.0/22
G,91.108.20.0/22
G,91.108.36.0/23
G,91.108.38.0/23
G,91.108.56.0/22
G,149.154.160.0/20
G,149.154.161.0/24
G,149.154.162.0/23
G,149.154.164.0/22
G,149.154.168.0/21
G,149.154.172.0/22
G,149.154.160.0/20
G,149.154.160.1/32
G,149.154.160.2/31
G,149.154.160.4/30
G,149.154.160.8/29
G,149.154.160.16/28
G,149.154.160.32/27
G,149.154.160.64/26
G,149.154.160.128/25
G,149.154.164.0/22
G,91.105.192.0/23
G,91.108.4.0/22
G,91.108.20.0/22
G,91.108.56.0/24
G,109.239.140.0/24
G,67.198.55.0/24
G,91.108.56.172
G,149.154.175.50
G,185.76.151.0/24
" | grep -E "^G" | cut -c3- | while read ip_addr; do echo "-A $dst4_dns_fw_type $ip_addr"; done | ipset -! restore &>/dev/null
	echo "~G,2001:b28:f23d::/48
~G,2001:b28:f23f::/48
~G,2001:67c:4e8::/48
~G,2001:b28:f23c::/48
~G,2a0a:f280::/32
" | grep -E "^~G" | cut -c4- | while read ip_addr; do echo "-A $dst6_dns_fw_type $ip_addr"; done | ipset -! restore &>/dev/null


	# wanlist dst IP 规则
	if is_true "$ipv4"; then
	cat $file_wanlist_ext | grep -E "^b" | cut -c3- | while read ip_addr; do echo "-A $dst4_bp_type $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_wanlist_ext | grep -E "^g" | cut -c3- | while read ip_addr; do echo "-A $dst4_fw_type $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_wanlist_ext | grep -E "^G" | cut -c3- | while read ip_addr; do echo "-A $dst4_dns_fw_type $ip_addr"; done | ipset -! restore &>/dev/null
	fi
	if is_true "$ipv6"; then
	cat $file_wanlist_ext | grep -E "^~b" | cut -c4- | while read ip_addr; do echo "-A $dst6_bp_type $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_wanlist_ext | grep -E "^~g" | cut -c4- | while read ip_addr; do echo "-A $dst6_fw_type $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_wanlist_ext | grep -E "^~G" | cut -c4- | while read ip_addr; do echo "-A $dst6_dns_fw_type $ip_addr"; done | ipset -! restore &>/dev/null
	fi

	# wanlist 域名 规则
	if [ -s /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf ] ; then
		# 删除自定义黑名单 (黑名单不走 gfwlist)
		cat $file_wanlist_ext | grep -E "^@g" | cut -c4- > /opt/app/ss_tproxy/tmp/awk_del_list_tmp
		awk_del_list /opt/app/ss_tproxy/tmp/awk_del_list_tmp /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		cat $file_wanlist_ext | grep -E "^@G" | cut -c4- > /opt/app/ss_tproxy/tmp/awk_del_list_tmp
		awk_del_list /opt/app/ss_tproxy/tmp/awk_del_list_tmp /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
	fi
	if [ -s /opt/app/ss_tproxy/rule/gfwlist_ip.txt ] ; then
	if is_true "$ipv4"; then
		cat /opt/app/ss_tproxy/rule/gfwlist_ip.txt | grep -v '^#' | sort -u | grep -v '^$' | grep -E -o '([0-9]+\.){3}[0-9/]+' | sed -e "s/^/-A $dst4_fw_type &/g" | ipset -! restore
	fi
	fi
	# 添加自定义黑名单 (黑名单改走 sstp_dst_fw sstp_dst_dns_fw)
	is_true "$ipv4" && cat $file_wanlist_ext | grep -E "^@g" | cut -c4- | awk '{printf("server=/%s/'"$dns4_fw_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
	is_true "$ipv6" && cat $file_wanlist_ext | grep -E "^@g" | cut -c4- | awk '{printf("server=/%s/'"$dns6_fw_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
	cat $file_wanlist_ext | grep -E "^@g" | cut -c4- | awk '{printf("ipset=/%s/'"$dst_fw_ipset_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
	is_true "$ipv4" && cat $file_wanlist_ext | grep -E "^@G" | cut -c4- | awk '{printf("server=/%s/'"$dns4_fw_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
	is_true "$ipv6" && cat $file_wanlist_ext | grep -E "^@G" | cut -c4- | awk '{printf("server=/%s/'"$dns6_fw_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
	cat $file_wanlist_ext | grep -E "^@G" | cut -c4- | awk '{printf("ipset=/%s/'"$dst_dns_fw_ipset_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf

	# smartdns IP 规则
	chinadns_ng_enable="`nvram get app_102`"
	smartdns_enable="`nvram get app_106`"
	if [ "$chinadns_ng_enable" == "1" ] && [ "$smartdns_enable" == "1" ] && [ -s /etc/storage/app_23.sh ] ; then
		touch /etc/storage/app_23.sh
		cat /etc/storage/app_23.sh | grep "^server" | grep office | grep -E -o '([0-9]+\.){3}[0-9]+' | while read ip_addr; do echo "-A $dst4_dns_fw_type $ip_addr"; done | ipset -! restore &>/dev/null
		is_true "$ipv4" && cat /etc/storage/app_23.sh | grep "^server" | grep office | grep -E -o 'https://.+/' | awk -F "/" '{print $3}' | awk '{printf("server=/%s/'"$dns4_fw_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		is_true "$ipv6" && cat /etc/storage/app_23.sh | grep "^server" | grep office | grep -E -o 'https://.+/' | awk -F "/" '{print $3}' | awk '{printf("server=/%s/'"$dns6_fw_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		cat /etc/storage/app_23.sh | grep "^server" | grep office | grep -E -o 'https://.+/' | awk -F "/" '{print $3}' | awk '{printf("ipset=/%s/'"$dst_dns_fw_ipset_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		cat /etc/storage/app_23.sh | grep "^server" | grep china  | grep -E -o '([0-9]+\.){3}[0-9]+' | while read ip_addr; do echo "-A $dst4_bp_type $ip_addr"; done | ipset -! restore &>/dev/null
		is_true "$ipv4" && cat /etc/storage/app_23.sh | grep "^server" | grep china  | grep -E -o 'https://.+/' | awk -F "/" '{print $3}' | awk '{printf("server=/%s/'"$dns4_bp_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		is_true "$ipv6" && cat /etc/storage/app_23.sh | grep "^server" | grep china  | grep -E -o 'https://.+/' | awk -F "/" '{print $3}' | awk '{printf("server=/%s/'"$dns6_bp_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
		cat /etc/storage/app_23.sh | grep "^server" | grep china  | grep -E -o 'https://.+/' | awk -F "/" '{print $3}' | awk '{printf("ipset=/%s/'"$dst_bp_ipset_type"'\n", $1 )}' >> /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf
	fi

	# lanlist src IP 规则
	if is_true "$ipv4"; then
	cat $file_lanlist_ext | grep -E "^b" | cut -c3- | while read ip_addr; do echo "-A sstp_src_bp $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_lanlist_ext | grep -E "^g" | cut -c3- | while read ip_addr; do echo "-A sstp_src_fw $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_lanlist_ext | grep -E "^n" | cut -c3- | while read ip_addr; do echo "-A sstp_src_ac $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_lanlist_ext | grep -E "^1" | cut -c3- | while read ip_addr; do echo "-A sstp_src_chn $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_lanlist_ext | grep -E "^2" | cut -c3- | while read ip_addr; do echo "-A sstp_src_gfw $ip_addr"; done | ipset -! restore &>/dev/null
	fi
	if is_true "$ipv6"; then
	cat $file_lanlist_ext | grep -E "^~b" | cut -c4- | while read ip_addr; do echo "-A sstp_src_bp6 $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_lanlist_ext | grep -E "^~g" | cut -c4- | while read ip_addr; do echo "-A sstp_src_fw6 $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_lanlist_ext | grep -E "^~n" | cut -c4- | while read ip_addr; do echo "-A sstp_src_ac6 $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_lanlist_ext | grep -E "^~1" | cut -c4- | while read ip_addr; do echo "-A sstp_src_chn6 $ip_addr"; done | ipset -! restore &>/dev/null
	cat $file_lanlist_ext | grep -E "^~2" | cut -c4- | while read ip_addr; do echo "-A sstp_src_gfw6 $ip_addr"; done | ipset -! restore &>/dev/null
	fi

	# lanlist mac 规则
	cat $file_lanlist_ext | grep -E '^@' | cut -c2- | while read mac_c; do
	mac="${mac_c:2}"; mac=$(echo $mac | sed s/://g| sed s/：//g | tr '[a-z]' '[A-Z]'); mac="${mac:0:2}:${mac:2:2}:${mac:4:2}:${mac:6:2}:${mac:8:2}:${mac:10:2}";
	if [ ! -z "$mac" ] ; then
		case "${mac_c:0:1}" in
			n|N)
				ipset -! -A sstp_mac_ac $mac
				;;
			g|G)
				ipset -! -A sstp_mac_fw $mac
				;;
			b|B)
				ipset -! -A sstp_mac_bp $mac
				;;
			1)
				ipset -! -A sstp_mac_chn $mac
				;;
			2)
				ipset -! -A sstp_mac_gfw $mac
				;;
		esac
	fi
	done
	is_true "$ipv4" && update_lanlist_mac "iptables" "nat"
	is_true "$ipv6" && update_lanlist_mac "ip6tables" "nat"
	is_enabled_udp && is_true "$ipv4" && update_lanlist_mac "iptables" "mangle"
	is_enabled_udp && is_true "$ipv6" && update_lanlist_mac "ip6tables" "mangle"

	# adbyby host 规则
	update_cflist_ipset /tmp/adbyby_host.conf /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf

	update_dnsmasq_file
}

update_lanlist_mac() {

cat $file_lanlist_ext | grep -E '^@' | cut -c2- | while read mac_c; do
mac="${mac_c:2}"; mac=$(echo $mac | sed s/://g| sed s/：//g | tr '[a-z]' '[A-Z]'); mac="${mac:0:2}:${mac:2:2}:${mac:4:2}:${mac:6:2}:${mac:8:2}:${mac:10:2}";
if [ ! -z "$mac" ] ; then
	case "${mac_c:0:1}" in
		n|N)
			$1 -t $2 -I SSTP_PREROUTING -m mac --mac-source $mac -j SSTP_WAN_AC
			;;
		g|G)
			$1 -t $2 -I SSTP_PREROUTING -m mac --mac-source $mac -j SSTP_WAN_FW
			;;
		b|B)
			$1 -t $2 -I SSTP_PREROUTING -m mac --mac-source $mac -j RETURN
			;;
		1)
			$1 -t $2 -I SSTP_PREROUTING -m mac --mac-source $mac -j SSTP_WAN_CHN
			;;
		2)
			$1 -t $2 -I SSTP_PREROUTING -m mac --mac-source $mac -j SSTP_WAN_GFW
			;;
	esac
fi
done
}

update_dnsmasq_file() {

mkdir -p /tmp/ss_tproxy/dnsmasq.d
rm -rf /tmp/ss/dnsmasq.d/*
dnsmasq_file="`ls -p /opt/app/ss_tproxy/dnsmasq.d | grep -v tmp | grep -v /`"
[ ! -z "$dnsmasq_file" ] && echo "$dnsmasq_file" | while read conf_file; do [ "$(cat /opt/app/ss_tproxy/dnsmasq.d/$conf_file | grep -c "server=\|ipset=")" != "0"  ] &&  ln -sf /opt/app/ss_tproxy/dnsmasq.d/$conf_file /tmp/ss_tproxy/dnsmasq.d/$conf_file ; done
restart_on_dhcpd
}

update_check_file() {
	[ ! -f /opt/app/ss_tproxy/tmp/update_check_time ] && echo -n "0" > /opt/app/ss_tproxy/tmp/update_check_time
	if [ $(($(date "+1%m%d%H%M") - $(cat /opt/app/ss_tproxy/tmp/update_check_time))) -ge 70000 ] || [ ! -s /opt/app/ss_tproxy/tmp/update_check_time ] ; then
		echo "update_check_file 开始新的 update_file"
		echo -n "$(date "+1%m%d%H%M")" > /opt/app/ss_tproxy/tmp/update_check_time
		update_gfwlist
		update_chnroute
		update_chnlist
		update_wanlanlist_ipset
	else
		echo "update_check_file 间隔少于7天直接返回"
		return
	fi
}

start_dnsserver() {
	start_dnsserver_dnsproxy
	start_dnsserver_confset
	return
}

start_dnsserver_dnsproxy() {

if is_chnlist_mode; then
	# 回国模式直接使用远端DNS走代理，停止使用 dnsproxy
	return
fi
[ "$dns_start_dnsproxy" = "1" ] && return
chinadns_enable=`nvram get app_1`
[ -z $chinadns_enable ] && chinadns_enable=0 && nvram set app_1=0
chinadns_ng_enable=`nvram get app_102`
[ -z $chinadns_ng_enable ] && chinadns_ng_enable=0 && nvram set app_102=0
chinadns_port=`nvram get app_6`
[ -z $chinadns_port ] && chinadns_port=8053 && nvram set app_6=8053
if [ "$chinadns_port" != "8053" ] ; then
chinadns_enable=0
chinadns_ng_enable=0
fi
if [ "$chinadns_enable" != "0" ] || [ "$chinadns_ng_enable" != "0" ] ; then
	ss_dnsproxy_x=2 ; nvram set ss_dnsproxy_x=2
else
	[ "$ss_dnsproxy_x" = "2" ] && ss_dnsproxy_x=0 && nvram set ss_dnsproxy_x=0
fi

if [ "$ss_dnsproxy_x" = "0" ] ; then
	for h_i in $(seq 1 2) ; do
	[[ "$(dnsproxy -h 2>&1 | wc -l)" -lt 2 ]] && rm -rf /opt/bin/dnsproxy
	[[ "$(dnsproxy -h 2>&1 | wc -l)" -lt 2 ]] && wgetcurl_file "/opt/bin/dnsproxy" "$hiboyfile/dnsproxy" "$hiboyfile2/dnsproxy"
	done
	logger -t "【sh_ss_tproxy.sh】" "启动 dnsproxy 防止域名污染"
	pidof dnsproxy >/dev/null 2>&1 && killall dnsproxy && killall -9 dnsproxy 2>/dev/null
	pidof pdnsd >/dev/null 2>&1 && killall pdnsd && killall -9 pdnsd 2>/dev/null
	if [ -s /sbin/dnsproxy ] ; then
		/sbin/dnsproxy -d
	else
		dnsproxy -d
	fi
	[ ! -z "`pidof dnsproxy`" ] && return
	logger -t "【sh_ss_tproxy.sh】" "错误 dnsproxy 没启动！"
	ss_dnsproxy_x=1 ; nvram set ss_dnsproxy_x=1
fi
if [ "$ss_dnsproxy_x" = "1" ] ; then
for h_i in $(seq 1 2) ; do
[[ "$(pdnsd -h 2>&1 | wc -l)" -lt 2 ]] && rm -rf /opt/bin/pdnsd
[[ "$(pdnsd -h 2>&1 | wc -l)" -lt 2 ]] && wgetcurl_file "/opt/bin/pdnsd" "$hiboyfile/pdnsd" "$hiboyfile2/pdnsd"
done
logger -t "【sh_ss_tproxy.sh】" "启动 pdnsd 防止域名污染"
pidof dnsproxy >/dev/null 2>&1 && killall dnsproxy && killall -9 dnsproxy 2>/dev/null
pidof pdnsd >/dev/null 2>&1 && killall pdnsd && killall -9 pdnsd 2>/dev/null
pdnsd_conf="/etc/storage/pdnsd.conf"
if [ ! -f "$pdnsd_conf" ] || [ ! -s "$pdnsd_conf" ] ; then
	cat > $pdnsd_conf <<-\END
global {
perm_cache=2048;
cache_dir="/var/pdnsd";
run_as="nobody";
server_port = 8053;
server_ip = 0.0.0.0;
status_ctl = on;
query_method=tcp_only;
min_ttl=1m;
max_ttl=1w;
timeout=5;
}

server {
label= "opendns";
ip = 208.67.222.222, 208.67.220.220;
port = 443;
root_server = on;
uptest= none;
}

server {
label= "google dns";
ip = 8.8.8.8, 8.8.4.4;
port = 53;
root_server = on;
uptest= none;
}

END
fi
chmod 755 $pdnsd_conf
CACHEDIR=/var/pdnsd
CACHE=$CACHEDIR/pdnsd.cache

USER=nobody
GROUP=nogroup

if ! test -f "$CACHE"; then
	mkdir -p `dirname $CACHE`
	dd if=/dev/zero of="$CACHE" bs=1 count=4 2> /dev/null
	chown -R $USER.$GROUP $CACHEDIR
fi
pdnsd -c $pdnsd_conf -p /var/run/pdnsd.pid &
[ ! -z "`pidof pdnsd`" ] && return
logger -t "【sh_ss_tproxy.sh】" "错误 pdnsd 没启动！"
ss_dnsproxy_x=2 ; nvram set ss_dnsproxy_x=2
fi
if [ "$ss_dnsproxy_x" = "2" ] && [ -s /etc/storage/script/Sh19_chinadns.sh ] ; then
if [ "$chinadns_port" = "8053" ] ; then
	/etc/storage/script/Sh09_chinadns_ng.sh stop
	sleep 1
	/etc/storage/script/Sh19_chinadns.sh stop
	sleep 1
	logger -t "【sh_ss_tproxy.sh】" "使用 dnsmasq ，第三方 DNS 程序防止域名污染"
	if [ "$chinadns_enable" == "0" ] && [ "$chinadns_ng_enable" == "0" ] ; then
	logger -t "【sh_ss_tproxy.sh】" "自动开启 ChinaDNS-NG 防止域名污染"
	nvram set app_102=1
	fi
	nvram set chinadns_status=""
	nvram set chinadns_ng_status=""
	/etc/storage/script/Sh09_chinadns_ng.sh
	sleep 1
	/etc/storage/script/Sh19_chinadns.sh
	sleep 5
else
	logger -t "【sh_ss_tproxy.sh】" "错误！！！ 第三方 DNS 程序 8053 端口没启动！"
	ss_dnsproxy_x=0 ; nvram set ss_dnsproxy_x=0
fi
fi

}

start_dnsserver_confset() {
sed -Ei '/no-resolv|server=127.0.0.1|dns-forward-max=1000|min-cache-ttl=1800|ss_tproxy/d' /etc/storage/dnsmasq/dnsmasq.conf
if [ "$ss_dnsproxy_x" != "2" ] ; then
sed -Ei '/chinadns_ng|chinadns_0/d' /etc/storage/dnsmasq/dnsmasq.conf
fi
sed ":a;N;s/\n\n\n/\n\n/g;ba" -i  /etc/storage/dnsmasq/dnsmasq.conf
echo "#ss_tproxy" >> /etc/storage/dnsmasq/dnsmasq.conf
if [ "$ss_pdnsd_all" = "1" ] ; then
	cat >> "/etc/storage/dnsmasq/dnsmasq.conf" <<-\EOF
no-resolv #ss_tproxy
server=127.0.0.1#8053 #ss_tproxy
EOF
fi
cat >> "/etc/storage/dnsmasq/dnsmasq.conf" <<-\EOF
dns-forward-max=1000 #ss_tproxy
min-cache-ttl=1800 #ss_tproxy
EOF
if is_chnlist_mode; then
	# 回国模式直接使用远端DNS走代理，停止使用 dnsproxy
	sed -Ei "/server=127.0.0.1#8053/d" /etc/storage/dnsmasq/dnsmasq.conf
#	echo "#server=127.0.0.1#8053 #ss_tproxy" >> /etc/storage/dnsmasq/dnsmasq.conf
	echo "server=${dns_remote:=8.8.8.8#53} #ss_tproxy" >> /etc/storage/dnsmasq/dnsmasq.conf
fi
is_true "$ipv6" && echo "server=${dns_remote6:=2001:4860:4860::8888#53} #ss_tproxy" >> /etc/storage/dnsmasq/dnsmasq.conf
sed -Ei "/conf-dir=\/tmp\/ss\/dnsmasq.d/d" /etc/storage/dnsmasq/dnsmasq.conf
sed -Ei "/conf-dir=\/opt\/app\/ss_tproxy\/dnsmasq.d/d" /etc/storage/dnsmasq/dnsmasq.conf
sed -Ei "/conf-dir=\/tmp\/ss_tproxy\/dnsmasq.d/d" /etc/storage/dnsmasq/dnsmasq.conf
mkdir -p $dnsmasq_conf_dir
echo "$(for conf_dir_arg in $dnsmasq_conf_dir; do [ -d $conf_dir_arg ] && echo "conf-dir=$conf_dir_arg #ss_tproxy"; done)" >> /etc/storage/dnsmasq/dnsmasq.conf
echo "$(for conf_file_arg in $dnsmasq_conf_file; do [ -s $conf_file_arg ] && echo "conf-file=$conf_file_arg #ss_tproxy"; done)" >> /etc/storage/dnsmasq/dnsmasq.conf
while read dnsmasq_string_arg; do
	if [ ! -z "$dnsmasq_string_arg" ]; then
		echo "$dnsmasq_string_arg #ss_tproxy" >> /etc/storage/dnsmasq/dnsmasq.conf
	fi
done < $dnsmasq_conf_string
update_dnsmasq_file
}

stop_dnsserver() {
sed -Ei '/no-resolv|server=127.0.0.1|dns-forward-max=1000|min-cache-ttl=1800|ss_tproxy/d' /etc/storage/dnsmasq/dnsmasq.conf
sed ":a;N;s/\n\n\n/\n\n/g;ba" -i  /etc/storage/dnsmasq/dnsmasq.conf
sed -Ei "/conf-dir=\/opt\/app\/ss_tproxy\/dnsmasq.d/d" /etc/storage/dnsmasq/dnsmasq.conf
update_md5_check stop_dnsserver_restart_dhcpd /etc/storage/dnsmasq/dnsmasq.conf
if is_md5_not ; then
update_dnsmasq_file
fi
killall pdnsd dnsproxy
killall -9 pdnsd dnsproxy
#	kill -9 $status_dnsmasq_pid  &>/dev/null
#	kill -9 $status_chinadns_pid &>/dev/null
#	kill -9 $status_dns2tcp4_pid &>/dev/null
#	kill -9 $status_dns2tcp6_pid &>/dev/null
#	delete_pidfile
}

flush_dnscache() {
	! ss_tproxy_is_started && return
#    kill -HUP "$status_dnsmasq_pid"
}

modify_resolvconf() {
	return
	if is_false "$opts_overwrite_resolv"; then
		while umount /etc/resolv.conf &>/dev/null; do true; done
		temp_resolv_conf="/opt/app/ss_tproxy/resolv.conf"
		touch $temp_resolv_conf
		chmod 0644 $temp_resolv_conf
		umount /etc/resolv.conf
		mount -o bind $temp_resolv_conf /etc/resolv.conf
		#rm -f $temp_resolv_conf
	fi
	echo "# Generated by ss-tproxy at $(date '+%F %T')" >/etc/resolv.conf
	is_true "$ipv4" && echo "nameserver 127.0.0.1" >>/etc/resolv.conf
	is_true "$ipv6" && echo "nameserver ::1" >>/etc/resolv.conf
	is_true "$ipv4" && DNS_china=`nvram get wan0_dns |cut -d ' ' -f1`
	is_true "$ipv4" && [ ! -z "$DNS_china" ] && echo "nameserver $DNS_china" >>/etc/resolv.conf
	is_true "$ipv6" && DNS6_china=`nvram get wan0_dns6 |cut -d ' ' -f1`
	is_true "$ipv6" && [ ! -z "$DNS6_china" ] && echo "nameserver $DNS6_china" >>/etc/resolv.conf
}

restore_resolvconf() {
	return
	if is_false "$opts_overwrite_resolv"; then
		while umount /etc/resolv.conf &>/dev/null; do true; done
	else
		echo "# Generated by ss-tproxy at $(date '+%F %T')" >/etc/resolv.conf
		is_true "$ipv4" && echo "nameserver $dns_direct" >>/etc/resolv.conf
		is_true "$ipv6" && echo "nameserver $dns_direct6" >>/etc/resolv.conf
	fi
}

start_proxy_proc() {
	eval "$proxy_startcmd" || log_error "failed to start local proxy process, exit-code: $?"
}

stop_proxy_proc() {
	eval "$proxy_stopcmd" &>/dev/null
}

enable_ipforward() {
	is_true "$ipv4" && set_sysctl_option 'net.ipv4.ip_forward' 1
	is_true "$ipv6" && set_sysctl_option 'net.ipv6.conf.all.forwarding' 1
}

disable_icmpredir() {
	for dir in /proc/sys/net/ipv4/conf/* ; do
		dir="$(basename "$dir")"
		set_sysctl_option "net.ipv4.conf.${dir//.//}.send_redirects" 0
	done
}

delete_gfwlist() {
	ss_tproxy_is_started && return
	is_true "$ipv4" && ipset -X gfwlist  &>/dev/null
	is_true "$ipv6" && ipset -X gfwlist6 &>/dev/null
}

delete_chnroute() {
	ipset -X localaddr  &>/dev/null
	ipset -X localaddr6 &>/dev/null
	ipset -X privaddr  &>/dev/null
	ipset -X privaddr6 &>/dev/null
	ipset -X chnroute  &>/dev/null
	ipset -X chnroute6 &>/dev/null
}

delete_iproute2() {
	is_true "$ipv4" && {
		ip -4 rule  del   table $ipts_rt_tab
		ip -4 route flush table $ipts_rt_tab
	} &>/dev/null

	is_true "$ipv6" && {
		ip -6 rule  del   table $ipts_rt_tab
		ip -6 route flush table $ipts_rt_tab
	} &>/dev/null
}

_flush_iptables() {
	$1 -t mangle -D PREROUTING  -j SSTP_PREROUTING  &>/dev/null
	$1 -t mangle -D OUTPUT      -j SSTP_OUTPUT      &>/dev/null
	$1 -t nat    -D PREROUTING  -j SSTP_PREROUTING  &>/dev/null
	$1 -t nat    -D OUTPUT      -j SSTP_OUTPUT      &>/dev/null
	$1 -t nat    -D POSTROUTING -j SSTP_POSTROUTING &>/dev/null

	$1 -t mangle -F SSTP_PREROUTING  &>/dev/null
	$1 -t mangle -X SSTP_PREROUTING  &>/dev/null
	$1 -t mangle -F SSTP_OUTPUT      &>/dev/null
	$1 -t mangle -X SSTP_OUTPUT      &>/dev/null
	$1 -t nat    -F SSTP_PREROUTING  &>/dev/null
	$1 -t nat    -X SSTP_PREROUTING  &>/dev/null
	$1 -t nat    -F SSTP_OUTPUT      &>/dev/null
	$1 -t nat    -X SSTP_OUTPUT      &>/dev/null
	$1 -t nat    -F SSTP_POSTROUTING &>/dev/null
	$1 -t nat    -X SSTP_POSTROUTING &>/dev/null

	$1 -t mangle -F SSTP_RULE &>/dev/null
	$1 -t mangle -X SSTP_RULE &>/dev/null
	$1 -t nat    -F SSTP_RULE &>/dev/null
	$1 -t nat    -X SSTP_RULE &>/dev/null

	$1 -t mangle -F SSTP_LAN_AC  &>/dev/null
	$1 -t mangle -X SSTP_LAN_AC  &>/dev/null
	$1 -t mangle -F SSTP_WAN_AC  &>/dev/null
	$1 -t mangle -X SSTP_WAN_AC  &>/dev/null
	$1 -t mangle -F SSTP_GFW_CHN &>/dev/null
	$1 -t mangle -X SSTP_GFW_CHN &>/dev/null
	$1 -t mangle -F SSTP_WAN_GFW &>/dev/null
	$1 -t mangle -X SSTP_WAN_GFW &>/dev/null
	$1 -t mangle -F SSTP_WAN_CHN &>/dev/null
	$1 -t mangle -X SSTP_WAN_CHN &>/dev/null
	$1 -t mangle -F SSTP_WAN_FW  &>/dev/null
	$1 -t mangle -X SSTP_WAN_FW  &>/dev/null
	$1 -t mangle -F SSTP_WAN_DNS  &>/dev/null
	$1 -t mangle -X SSTP_WAN_DNS  &>/dev/null
	$1 -t nat    -F SSTP_LAN_AC  &>/dev/null
	$1 -t nat    -X SSTP_LAN_AC  &>/dev/null
	$1 -t nat    -F SSTP_WAN_AC  &>/dev/null
	$1 -t nat    -X SSTP_WAN_AC  &>/dev/null
	$1 -t nat    -F SSTP_GFW_CHN &>/dev/null
	$1 -t nat    -X SSTP_GFW_CHN &>/dev/null
	$1 -t nat    -F SSTP_WAN_GFW &>/dev/null
	$1 -t nat    -X SSTP_WAN_GFW &>/dev/null
	$1 -t nat    -F SSTP_WAN_CHN &>/dev/null
	$1 -t nat    -X SSTP_WAN_CHN &>/dev/null
	$1 -t nat    -F SSTP_WAN_FW  &>/dev/null
	$1 -t nat    -X SSTP_WAN_FW  &>/dev/null
	$1 -t nat    -F SSTP_WAN_DNS  &>/dev/null
	$1 -t nat    -X SSTP_WAN_DNS  &>/dev/null
}

flush_iptables() {
	is_true "$ipv4" && _flush_iptables "iptables"
	is_true "$ipv6" && _flush_iptables "ip6tables"
	[ ! -z "$(ip6tables -vnL INPUT --line-numbers | grep -Ei "udp *dpt:53 *reject")" ] && ip6tables -D INPUT -p udp --dport 53 -j REJECT
}

_show_iptables() {
	echo "$(color_green "==> $1-mangle <==")"
	$1 -t mangle -nvL --line-numbers
	echo
	echo "$(color_green "==> $1-nat <==")"
	$1 -t nat -nvL --line-numbers
}

show_iptables() {
	is_true "$ipv4" && _show_iptables "iptables"
	{ is_true "$ipv4" && is_true "$ipv6"; } && echo
	is_true "$ipv6" && _show_iptables "ip6tables"
}

check_dnsredir() {
	is_false "$ipts_reddns_onstop" && return

	is_ipv4_ipts $1 && direct_dns_ip="$dns_direct" || direct_dns_ip="$dns_direct6"
	[ ! -z "$ipts_reddns_ip" ] && is_ipv4_ipts $1 && direct_dns_ip="$ipts_reddns_ip"

	$1 -t nat -N SSTP_PREROUTING  &>/dev/null
	$1 -t nat -A SSTP_PREROUTING  -m set ! --match-set $localaddr_setname src -p udp --dport 53 -j DNAT --to-destination $direct_dns_ip
	$1 -t nat -N SSTP_POSTROUTING &>/dev/null
	$1 -t nat -A SSTP_POSTROUTING -m set ! --match-set $localaddr_setname src -p udp -d $direct_dns_ip --dport 53 -j MASQUERADE &>/dev/null
}

check_startdnsredir() {
	is_false "$ipts_reddns_onstart" && return

	is_ipv4_ipts $1 && direct_dns_ip="${dns4_fw_type%%#*}" || direct_dns_ip="${dns6_fw_type%%#*}"
	[ ! -z "$ipts_reddns_ip" ] && is_ipv4_ipts $1 && direct_dns_ip="$ipts_reddns_ip"

	$1 -t nat -N SSTP_PREROUTING  &>/dev/null
	$1 -t nat -I SSTP_PREROUTING  -m set ! --match-set $localaddr_setname src -p udp --dport 53 -j DNAT --to-destination $direct_dns_ip
	$1 -t nat -N SSTP_POSTROUTING &>/dev/null
	$1 -t nat -A SSTP_POSTROUTING -m set ! --match-set $localaddr_setname src -p udp -d $direct_dns_ip --dport 53 -j MASQUERADE &>/dev/null
}

check_snatrule() {
	set_snat_rule='false'
	{ is_ipv4_ipts $1 && is_true "$ipts_set_snat";  } && set_snat_rule='true'
	{ is_ipv6_ipts $1 && is_true "$ipts_set_snat6"; } && set_snat_rule='true'
	is_false "$set_snat_rule" && return

	$1 -t nat -N SSTP_POSTROUTING &>/dev/null
	$1 -t nat -A SSTP_POSTROUTING -m set ! --match-set $localaddr_setname src -m conntrack --ctstate SNAT,DNAT   -j RETURN
	$1 -t nat -A SSTP_POSTROUTING -m set ! --match-set $localaddr_setname src -p tcp --syn                       -j MASQUERADE
	$1 -t nat -A SSTP_POSTROUTING -m set ! --match-set $localaddr_setname src -p udp -m conntrack --ctstate NEW  -j MASQUERADE
	$1 -t nat -A SSTP_POSTROUTING -m set ! --match-set $localaddr_setname src -p icmp -m conntrack --ctstate NEW -j MASQUERADE
}

check_iptschain() {
	$1 -t nat -nL SSTP_PREROUTING  &>/dev/null && $1 -t nat -A PREROUTING  -j SSTP_PREROUTING
	$1 -t nat -nL SSTP_POSTROUTING &>/dev/null && $1 -t nat -I POSTROUTING -j SSTP_POSTROUTING
}

check_postrule() {
	ss_tproxy_is_started && return
	{ is_false "$ipts_reddns_onstop" && is_false "$ipts_set_snat" && is_false "$ipts_set_snat6"; } && return
	is_true "$ipv4" && { check_dnsredir "iptables";  check_snatrule "iptables";  check_iptschain "iptables";  }
	is_true "$ipv6" && { check_dnsredir "ip6tables"; check_snatrule "ip6tables"; check_iptschain "ip6tables"; }
}

_flush_postrule() {
	$1 -t nat -D PREROUTING  -j SSTP_PREROUTING  &>/dev/null
	$1 -t nat -D POSTROUTING -j SSTP_POSTROUTING &>/dev/null
	$1 -t nat -F SSTP_PREROUTING  &>/dev/null
	$1 -t nat -X SSTP_PREROUTING  &>/dev/null
	$1 -t nat -F SSTP_POSTROUTING &>/dev/null
	$1 -t nat -X SSTP_POSTROUTING &>/dev/null
}

flush_postrule() {
	ss_tproxy_is_started && return
	is_true "$ipv4" && _flush_postrule "iptables"
	is_true "$ipv6" && _flush_postrule "ip6tables"
}

_delete_unused_iptchains() {
	if is_empty_iptschain $1 mangle SSTP_PREROUTING; then
		$1 -t mangle -D PREROUTING -j SSTP_PREROUTING
		$1 -t mangle -X SSTP_PREROUTING
	fi
	if is_empty_iptschain $1 mangle SSTP_OUTPUT; then
		$1 -t mangle -D OUTPUT -j SSTP_OUTPUT
		$1 -t mangle -X SSTP_OUTPUT
	fi
	if is_empty_iptschain $1 nat SSTP_PREROUTING; then
		$1 -t nat -D PREROUTING -j SSTP_PREROUTING
		$1 -t nat -X SSTP_PREROUTING
	fi
	if is_empty_iptschain $1 nat SSTP_OUTPUT; then
		$1 -t nat -D OUTPUT -j SSTP_OUTPUT
		$1 -t nat -X SSTP_OUTPUT
	fi
	if is_empty_iptschain $1 nat SSTP_POSTROUTING; then
		$1 -t nat -D POSTROUTING -j SSTP_POSTROUTING
		$1 -t nat -X SSTP_POSTROUTING
	fi
}

delete_unused_iptchains() {
	is_true "$ipv4" && _delete_unused_iptchains "iptables"
	is_true "$ipv6" && _delete_unused_iptchains "ip6tables"
}

start_iptables_pre_rules() {
	$1 -t mangle -N SSTP_PREROUTING
	$1 -t mangle -N SSTP_OUTPUT
	$1 -t nat    -N SSTP_PREROUTING
	$1 -t nat    -N SSTP_OUTPUT
	$1 -t nat    -N SSTP_POSTROUTING

	if is_need_iproute; then
		is_ipv4_ipts $1 && iproute2_family="-4" || iproute2_family="-6"
		ip $iproute2_family route add local default dev $ipts_if_lo table $ipts_rt_tab
		ip $iproute2_family rule  add fwmark $ipts_rt_mark          table $ipts_rt_tab
	fi
}

start_iptables_post_rules() {
	$1 -t mangle -I PREROUTING  $wifidogn_manglex -j SSTP_PREROUTING
	$1 -t mangle -A OUTPUT      -j SSTP_OUTPUT
	$1 -t nat    -I PREROUTING  $wifidognx -j SSTP_PREROUTING
	$1 -t nat    -I OUTPUT      $wifidognx_output -j SSTP_OUTPUT
	$1 -t nat    -I POSTROUTING -j SSTP_POSTROUTING
}

start_iptables_tproxy_mode() {
	is_ipv4_ipts $1 && loopback_addr="127.0.0.1" || loopback_addr="::1"

	is_ipv4_ipts $1 && lan_ipaddr="$lan_ipv4_ipaddr" || lan_ipaddr="$lan_ipv6_ipaddr"

	is_ipv4_ipts $1 && gfwlist_setname="gfwlist" || gfwlist_setname="gfwlist6"

	is_ipv4_ipts $1 && gfwlist_setfamily="inet" || gfwlist_setfamily="inet6"

	is_ipv4_ipts $1 && grep_pattern="^-" || grep_pattern="^~"

	is_ipv4_ipts $1 && proxyaddr_setname="proxyaddr" || proxyaddr_setname="proxyaddr6"

	is_ipv4_ipts $1 && direct_dns_ip="$dns_direct" || direct_dns_ip="$dns_direct6"

	is_ipv4_ipts $1 && remote_dns_ip="${dns_remote%%#*}" || remote_dns_ip="${dns_remote6%%#*}"
	is_ipv4_ipts $1 && remote_dns_port="${dns_remote##*#}" || remote_dns_port="${dns_remote6##*#}"

	is_ipv4_ipts $1 && chnroute_setname="chnroute" || chnroute_setname="chnroute6"

	is_ipv4_ipts $1 && privaddr_setname="privaddr" || privaddr_setname="privaddr6"

	is_ipv4_ipts $1 && localaddr_setname="localaddr" || localaddr_setname="localaddr6"

	ipset -! -N $localaddr_setname hash:net hashsize 64 family $gfwlist_setfamily
	ipset -! -N $privaddr_setname hash:net hashsize 64 family $gfwlist_setfamily
	ipset -! -N $chnroute_setname hash:net family $gfwlist_setfamily &>/dev/null
	ipset -! -N $gfwlist_setname hash:net family $gfwlist_setfamily &>/dev/null
	cat $file_gfwlist_ext | grep -E "$grep_pattern" | cut -c2- | while read ip_addr; do echo "-A $gfwlist_setname $ip_addr"; done | ipset -! restore &>/dev/null

	# src 规则
	is_ipv4_ipts $1 && sstp_src_ac_setname="sstp_src_ac" || sstp_src_ac_setname="sstp_src_ac6"

	is_ipv4_ipts $1 && sstp_src_bp_setname="sstp_src_bp" || sstp_src_bp_setname="sstp_src_bp6"

	is_ipv4_ipts $1 && sstp_src_fw_setname="sstp_src_fw" || sstp_src_fw_setname="sstp_src_fw6"

	is_ipv4_ipts $1 && sstp_src_gfw_setname="sstp_src_gfw" || sstp_src_gfw_setname="sstp_src_gfw6"

	is_ipv4_ipts $1 && sstp_src_chn_setname="sstp_src_chn" || sstp_src_chn_setname="sstp_src_chn6"

	
	#ipset -X $sstp_src_bp_setname &>/dev/null
	ipset -! -N $sstp_src_bp_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_src_fw_setname &>/dev/null
	ipset -! -N $sstp_src_fw_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_src_ac_setname &>/dev/null
	ipset -! -N $sstp_src_ac_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_src_chn_setname &>/dev/null
	ipset -! -N $sstp_src_chn_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_src_gfw_setname &>/dev/null
	ipset -! -N $sstp_src_gfw_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null

	# dst 规则
	is_ipv4_ipts $1 && sstp_dst_bp_setname="sstp_dst_bp" || sstp_dst_bp_setname="sstp_dst_bp6"

	is_ipv4_ipts $1 && sstp_dst_fw_setname="sstp_dst_fw" || sstp_dst_fw_setname="sstp_dst_fw6"

	is_ipv4_ipts $1 && sstp_dst_dns_fw_setname="sstp_dst_dns_fw" || sstp_dst_dns_fw_setname="sstp_dst_dns_fw6"

	#ipset -X $sstp_dst_bp_setname &>/dev/null
	ipset -! -N $sstp_dst_bp_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_dst_fw_setname &>/dev/null
	ipset -! -N $sstp_dst_fw_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_dst_dns_fw_setname &>/dev/null
	ipset -! -N $sstp_dst_dns_fw_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null

	######################### SSTP_RULE (tcp and udp) #########################

	$1 -t mangle -N SSTP_RULE
	$1 -t mangle -N SSTP_LAN_AC
	$1 -t mangle -N SSTP_WAN_AC
	$1 -t mangle -N SSTP_WAN_CHN
	$1 -t mangle -N SSTP_WAN_GFW
	$1 -t mangle -N SSTP_GFW_CHN
	$1 -t mangle -N SSTP_WAN_FW
	$1 -t mangle -N SSTP_WAN_DNS

	$1 -t mangle -A SSTP_RULE -j CONNMARK --restore-mark
	$1 -t mangle -A SSTP_RULE -m mark --mark $ipts_rt_mark -j RETURN
	$1 -t mangle -A SSTP_RULE -m mark --mark 0xff -j RETURN
	$1 -t mangle -A SSTP_RULE -m set --match-set $privaddr_setname dst -j RETURN

	$1 -t mangle -A SSTP_RULE -p tcp -m set --match-set $proxyaddr_setname dst -m multiport --dports $proxy_svrport -j RETURN
	is_enabled_udp && $1 -t mangle -A SSTP_RULE -p udp -m set --match-set $proxyaddr_setname dst -m multiport --dports $proxy_svrport -j RETURN

	if is_enabled_udp; then
		$1 -t mangle -A SSTP_RULE -p udp -d $direct_dns_ip --dport 53               -j RETURN
		$1 -t mangle -A SSTP_RULE -p udp -d $remote_dns_ip --dport $remote_dns_port -j MARK --set-mark $ipts_rt_mark
		$1 -t mangle -A SSTP_RULE -p udp -d $remote_dns_ip --dport $remote_dns_port -j RETURN
	else
		$1 -t mangle -A SSTP_RULE -p tcp -d $remote_dns_ip --dport $remote_dns_port -j MARK --set-mark $ipts_rt_mark
		$1 -t mangle -A SSTP_RULE -p tcp -d $remote_dns_ip --dport $remote_dns_port -j RETURN
	fi

	$1 -t mangle -A SSTP_RULE -j SSTP_LAN_AC
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_bp src -j RETURN
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_fw src -j SSTP_WAN_FW
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_ac src -j SSTP_WAN_AC
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_gfw src -j SSTP_WAN_GFW
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_chn src -j SSTP_WAN_CHN
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_bp_setname src -j RETURN
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_fw_setname src -j SSTP_WAN_FW
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_ac_setname src -j SSTP_WAN_AC
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_gfw_setname src -j SSTP_WAN_GFW
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_chn_setname src -j SSTP_WAN_CHN
	if [ "$LAN_AC_IP" == "2" ] ; then
	$1 -t mangle -A SSTP_LAN_AC -m set ! --match-set $localaddr_setname src -j RETURN
	$1 -t mangle -A SSTP_LAN_AC -m set --match-set $localaddr_setname src -j SSTP_WAN_AC
	else
	$1 -t mangle -A SSTP_LAN_AC -j ${LAN_TARGET:=SSTP_WAN_AC}
	fi
	$1 -t mangle -A SSTP_WAN_AC -j ${MODE_TARGET:=RETURN}
	$1 -t mangle -A SSTP_GFW_CHN -j SSTP_WAN_GFW
	$1 -t mangle -A SSTP_GFW_CHN -j SSTP_WAN_CHN
	$1 -t mangle -A SSTP_GFW_CHN -j RETURN
	is_enabled_udp && [ "$ss_all_udp" == "1" ] && $1 -t mangle -A SSTP_WAN_GFW -p udp -j SSTP_WAN_FW
	$1 -t mangle -A SSTP_WAN_GFW -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
	$1 -t mangle -A SSTP_WAN_GFW -m set --match-set $sstp_dst_fw_setname dst -j SSTP_WAN_FW
	$1 -t mangle -A SSTP_WAN_GFW -m set --match-set $sstp_dst_bp_setname dst -j RETURN
	$1 -t mangle -A SSTP_WAN_GFW -m set --match-set $gfwlist_setname dst -j ${GFWLIST_TARGET:=SSTP_WAN_FW}
	$1 -t mangle -A SSTP_WAN_GFW -j RETURN
	is_enabled_udp && [ "$ss_all_udp" == "1" ] && $1 -t mangle -A SSTP_WAN_CHN -p udp -j SSTP_WAN_FW
	$1 -t mangle -A SSTP_WAN_CHN -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
	$1 -t mangle -A SSTP_WAN_CHN -m set --match-set $sstp_dst_fw_setname dst -j SSTP_WAN_FW
	$1 -t mangle -A SSTP_WAN_CHN -m set --match-set $sstp_dst_bp_setname dst -j RETURN
	$1 -t mangle -A SSTP_WAN_CHN -m set --match-set $chnroute_setname dst -j ${CHN_TARGET:=RETURN}
	$1 -t mangle -A SSTP_WAN_CHN -j ${CHN_WAN_TARGET:=SSTP_WAN_FW}
	$1 -t mangle -A SSTP_WAN_FW -p tcp -m multiport --dports $ipts_proxy_dst_port_tcp --syn -j MARK --set-mark $ipts_rt_mark
	is_enabled_udp && $1 -t mangle -A SSTP_WAN_FW -p udp -m multiport --dports $ipts_proxy_dst_port_udp -m conntrack --ctstate NEW -j MARK --set-mark $ipts_rt_mark

	$1 -t mangle -A SSTP_WAN_FW -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
	$1 -t mangle -A SSTP_WAN_DNS -p tcp -m multiport --dports 1:65535 --syn -j MARK --set-mark $ipts_rt_mark
	is_enabled_udp && $1 -t mangle -A SSTP_WAN_DNS -p udp -m multiport --dports 1:65535 -m conntrack --ctstate NEW -j MARK --set-mark $ipts_rt_mark

	$1 -t mangle -A SSTP_RULE -j CONNMARK --save-mark

	######################### SSTP_OUTPUT/SSTP_PREROUTING #########################

	if is_usrgrp_mode; then
		$1 -t mangle -I SSTP_OUTPUT -m owner $(get_usrgrp_args) -j RETURN
	fi

	if is_nonstd_dnsport "$dnsmasq_bind_port"; then
		if [ "$lan_ipaddr" != "$loopback_addr" ] ; then
			$1 -t nat -A SSTP_OUTPUT -p udp -d $lan_ipaddr --dport 53 -j REDIRECT --to-ports $dnsmasq_bind_port
		else
			$1 -t nat -A SSTP_OUTPUT -p udp -d $loopback_addr --dport 53 -j REDIRECT --to-ports $dnsmasq_bind_port
		fi
	fi

	$1 -t mangle -A SSTP_OUTPUT -m set --match-set $localaddr_setname src -m set ! --match-set $localaddr_setname dst -p tcp -j SSTP_RULE
	is_enabled_udp && $1 -t mangle -A SSTP_OUTPUT -m set --match-set $localaddr_setname src -m set ! --match-set $localaddr_setname dst -p udp -j SSTP_RULE

	$1 -t mangle -A SSTP_PREROUTING -i $ipts_if_lo -m mark ! --mark $ipts_rt_mark -j RETURN

	if is_false "$selfonly"; then
		if is_nonstd_dnsport "$dnsmasq_bind_port"; then
			is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -m set ! --match-set $localaddr_setname src -m set --match-set $localaddr_setname dst -p udp --dport 53 -j RETURN
			$1 -t nat -A SSTP_PREROUTING -m set ! --match-set $localaddr_setname src -m set --match-set $localaddr_setname dst -p udp --dport 53 -j REDIRECT --to-ports $dnsmasq_bind_port
		fi

		$1 -t mangle -A SSTP_PREROUTING -m set ! --match-set $localaddr_setname src -m set ! --match-set $localaddr_setname dst -p tcp -j SSTP_RULE
		is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -m set ! --match-set $localaddr_setname src -m set ! --match-set $localaddr_setname dst -p udp -j SSTP_RULE
	fi

	if [ "$lan_ipaddr" != "$loopback_addr" ] ; then
		$1 -t mangle -A SSTP_PREROUTING -p tcp -m mark --mark $ipts_rt_mark -j TPROXY --on-ip $lan_ipaddr --on-port $proxy_tcpport
		is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -p udp -m mark --mark $ipts_rt_mark -j TPROXY --on-ip $lan_ipaddr --on-port $proxy_udpport
	else
		$1 -t mangle -A SSTP_PREROUTING -p tcp -m mark --mark $ipts_rt_mark -j TPROXY --on-ip $loopback_addr --on-port $proxy_tcpport
		is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -p udp -m mark --mark $ipts_rt_mark -j TPROXY --on-ip $loopback_addr --on-port $proxy_udpport
	fi

	check_snatrule $1
}

start_iptables_redirect_mode() {
	is_ipv4_ipts $1 && loopback_addr="127.0.0.1" || loopback_addr="::1"
	
	is_ipv4_ipts $1 && lan_ipaddr="$lan_ipv4_ipaddr" || lan_ipaddr="$lan_ipv6_ipaddr"
	
	is_ipv4_ipts $1 && gfwlist_setname="gfwlist" || gfwlist_setname="gfwlist6"

	is_ipv4_ipts $1 && gfwlist_setfamily="inet" || gfwlist_setfamily="inet6"

	is_ipv4_ipts $1 && grep_pattern="^-" || grep_pattern="^~"

	is_ipv4_ipts $1 && proxyaddr_setname="proxyaddr" || proxyaddr_setname="proxyaddr6"

	is_ipv4_ipts $1 && direct_dns_ip="$dns_direct" || direct_dns_ip="$dns_direct6"

	is_ipv4_ipts $1 && remote_dns_ip="${dns_remote%%#*}" || remote_dns_ip="${dns_remote6%%#*}"
	is_ipv4_ipts $1 && remote_dns_port="${dns_remote##*#}" || remote_dns_port="${dns_remote6##*#}"

	is_ipv4_ipts $1 && chnroute_setname="chnroute" || chnroute_setname="chnroute6"

	is_ipv4_ipts $1 && privaddr_setname="privaddr" || privaddr_setname="privaddr6"

	is_ipv4_ipts $1 && localaddr_setname="localaddr" || localaddr_setname="localaddr6"

	ipset -! -N $localaddr_setname hash:net hashsize 64 family $gfwlist_setfamily
	ipset -! -N $privaddr_setname hash:net hashsize 64 family $gfwlist_setfamily
	ipset -! -N $chnroute_setname hash:net family $gfwlist_setfamily &>/dev/null
	ipset -! -N $gfwlist_setname hash:net family $gfwlist_setfamily &>/dev/null
	cat $file_gfwlist_ext | grep -E "$grep_pattern" | cut -c2- | while read ip_addr; do echo "-A $gfwlist_setname $ip_addr"; done | ipset -! restore &>/dev/null

	# src 规则
	is_ipv4_ipts $1 && sstp_src_ac_setname="sstp_src_ac" || sstp_src_ac_setname="sstp_src_ac6"

	is_ipv4_ipts $1 && sstp_src_bp_setname="sstp_src_bp" || sstp_src_bp_setname="sstp_src_bp6"

	is_ipv4_ipts $1 && sstp_src_fw_setname="sstp_src_fw" || sstp_src_fw_setname="sstp_src_fw6"

	is_ipv4_ipts $1 && sstp_src_gfw_setname="sstp_src_gfw" || sstp_src_gfw_setname="sstp_src_gfw6"

	is_ipv4_ipts $1 && sstp_src_chn_setname="sstp_src_chn" || sstp_src_chn_setname="sstp_src_chn6"

	
	#ipset -X $sstp_src_bp_setname &>/dev/null
	ipset -! -N $sstp_src_bp_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_src_fw_setname &>/dev/null
	ipset -! -N $sstp_src_fw_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_src_ac_setname &>/dev/null
	ipset -! -N $sstp_src_ac_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_src_chn_setname &>/dev/null
	ipset -! -N $sstp_src_chn_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_src_gfw_setname &>/dev/null
	ipset -! -N $sstp_src_gfw_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null

	# dst 规则
	is_ipv4_ipts $1 && sstp_dst_bp_setname="sstp_dst_bp" || sstp_dst_bp_setname="sstp_dst_bp6"

	is_ipv4_ipts $1 && sstp_dst_fw_setname="sstp_dst_fw" || sstp_dst_fw_setname="sstp_dst_fw6"

	is_ipv4_ipts $1 && sstp_dst_dns_fw_setname="sstp_dst_dns_fw" || sstp_dst_dns_fw_setname="sstp_dst_dns_fw6"

	#ipset -X $sstp_dst_bp_setname &>/dev/null
	ipset -! -N $sstp_dst_bp_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_dst_fw_setname &>/dev/null
	ipset -! -N $sstp_dst_fw_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null
	#ipset -X $sstp_dst_dns_fw_setname &>/dev/null
	ipset -! -N $sstp_dst_dns_fw_setname hash:net hashsize 64 family $gfwlist_setfamily &>/dev/null

	######################### SSTP_RULE (for tcp) #########################

	$1 -t nat -N SSTP_RULE
	$1 -t nat -N SSTP_LAN_AC
	$1 -t nat -N SSTP_WAN_AC
	$1 -t nat -N SSTP_WAN_CHN
	$1 -t nat -N SSTP_WAN_GFW
	$1 -t nat -N SSTP_GFW_CHN
	$1 -t nat -N SSTP_WAN_FW
	$1 -t nat -N SSTP_WAN_DNS

	$1 -t nat -A SSTP_RULE -p tcp -m set --match-set $proxyaddr_setname dst -m multiport --dports $proxy_svrport -j RETURN
	$1 -t nat -A SSTP_RULE -m mark --mark 0xff -j RETURN
	$1 -t nat -A SSTP_RULE -m set --match-set $privaddr_setname dst -j RETURN

	if ! is_enabled_udp; then
		$1 -t nat -A SSTP_RULE -p tcp -d $remote_dns_ip --dport $remote_dns_port --syn -j REDIRECT --to-ports $proxy_tcpport
	fi
	$1 -t nat -A SSTP_RULE -j SSTP_LAN_AC
	$1 -t nat -A SSTP_LAN_AC -m set --match-set sstp_mac_bp src -j RETURN
	$1 -t nat -A SSTP_LAN_AC -m set --match-set sstp_mac_fw src -j SSTP_WAN_FW
	$1 -t nat -A SSTP_LAN_AC -m set --match-set sstp_mac_ac src -j SSTP_WAN_AC
	$1 -t nat -A SSTP_LAN_AC -m set --match-set sstp_mac_gfw src -j SSTP_WAN_GFW
	$1 -t nat -A SSTP_LAN_AC -m set --match-set sstp_mac_chn src -j SSTP_WAN_CHN
	$1 -t nat -A SSTP_LAN_AC -m set --match-set $sstp_src_bp_setname src -j RETURN
	$1 -t nat -A SSTP_LAN_AC -m set --match-set $sstp_src_fw_setname src -j SSTP_WAN_FW
	$1 -t nat -A SSTP_LAN_AC -m set --match-set $sstp_src_ac_setname src -j SSTP_WAN_AC
	$1 -t nat -A SSTP_LAN_AC -m set --match-set $sstp_src_gfw_setname src -j SSTP_WAN_GFW
	$1 -t nat -A SSTP_LAN_AC -m set --match-set $sstp_src_chn_setname src -j SSTP_WAN_CHN
	if [ "$LAN_AC_IP" == "2" ] ; then
	$1 -t nat -A SSTP_LAN_AC -m set ! --match-set $localaddr_setname src -j RETURN
	$1 -t nat -A SSTP_LAN_AC -m set --match-set $localaddr_setname src -j SSTP_WAN_AC
	else
	$1 -t nat -A SSTP_LAN_AC -j ${LAN_TARGET:=SSTP_WAN_AC}
	fi
	$1 -t nat -A SSTP_WAN_AC -j ${MODE_TARGET:=RETURN}
	$1 -t nat -A SSTP_GFW_CHN -j SSTP_WAN_GFW
	$1 -t nat -A SSTP_GFW_CHN -j SSTP_WAN_CHN
	$1 -t nat -A SSTP_GFW_CHN -j RETURN
	$1 -t nat -A SSTP_WAN_GFW -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
	$1 -t nat -A SSTP_WAN_GFW -m set --match-set $sstp_dst_fw_setname dst -j SSTP_WAN_FW
	$1 -t nat -A SSTP_WAN_GFW -m set --match-set $sstp_dst_bp_setname dst -j RETURN
	$1 -t nat -A SSTP_WAN_GFW -m set --match-set $gfwlist_setname dst -j ${GFWLIST_TARGET:=SSTP_WAN_FW}
	$1 -t nat -A SSTP_WAN_GFW -j RETURN
	$1 -t nat -A SSTP_WAN_CHN -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
	$1 -t nat -A SSTP_WAN_CHN -m set --match-set $sstp_dst_fw_setname dst -j SSTP_WAN_FW
	$1 -t nat -A SSTP_WAN_CHN -m set --match-set $sstp_dst_bp_setname dst -j RETURN
	$1 -t nat -A SSTP_WAN_CHN -m set --match-set $chnroute_setname dst -j ${CHN_TARGET:=RETURN}
	$1 -t nat -A SSTP_WAN_CHN -j ${CHN_WAN_TARGET:=SSTP_WAN_FW}
	$1 -t nat -A SSTP_WAN_FW -p tcp -m multiport --dports $ipts_proxy_dst_port_tcp --syn -j REDIRECT --to-ports $proxy_tcpport

	$1 -t nat -A SSTP_WAN_FW -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
	$1 -t nat -A SSTP_WAN_DNS -p tcp -m multiport --dports 1:65535 --syn -j REDIRECT --to-ports $proxy_tcpport

	if is_ipv4_ipts $1; then
		koolproxy_enable=`nvram get koolproxy_enable`
		if [ "$koolproxy_enable" != "0" ] ; then
		# 加载 kp过滤方案 规则
		logger -t "【SS】" "设置内网(LAN)访问控制【kp过滤方案】"
		cat $file_lanlist_ext | sort -u | grep -v '^$' | grep -v '^@' | grep -v '^#' | while read ip_addr
		do
		if [ ! -z "$ip_addr" ] ; then
			case "${ip_addr:0:1}" in
				1|1)
					iptables -t nat -I SSTP_LAN_AC  -p tcp -m mark --mark $(echo ${ip_addr:2} | awk -F "." '{printf ("0x%02x", $1)} {printf ("%02x", $2)} {printf ("%02x", $3)} {printf ("00/0xffffff00\n")}') $EXT_ARGS_TCP -j SSTP_WAN_CHN
					;;
				2|2)
					iptables -t nat -I SSTP_LAN_AC  -p tcp -m mark --mark $(echo ${ip_addr:2} | awk -F "." '{printf ("0x%02x", $1)} {printf ("%02x", $2)} {printf ("%02x", $3)} {printf ("00/0xffffff00\n")}') $EXT_ARGS_TCP -j SSTP_WAN_GFW
					;;
				n|N)
					iptables -t nat -I SSTP_LAN_AC  -p tcp -m mark --mark $(echo ${ip_addr:2} | awk -F "." '{printf ("0x%02x", $1)} {printf ("%02x", $2)} {printf ("%02x", $3)} {printf ("00/0xffffff00\n")}') $EXT_ARGS_TCP -j SSTP_WAN_AC
					;;
				g|G)
					iptables -t nat -I SSTP_LAN_AC  -p tcp -m mark --mark $(echo ${ip_addr:2} | awk -F "." '{printf ("0x%02x", $1)} {printf ("%02x", $2)} {printf ("%02x", $3)} {printf ("00/0xffffff00\n")}') $EXT_ARGS_TCP -j SSTP_WAN_FW
					;;
				b|B)
					iptables -t nat -I SSTP_LAN_AC  -p tcp -m mark --mark $(echo ${ip_addr:2} | awk -F "." '{printf ("0x%02x", $1)} {printf ("%02x", $2)} {printf ("%02x", $3)} {printf ("00/0xffffff00\n")}') -j RETURN
					;;
			esac
		fi
		done
		fi
	fi

	######################### SSTP_RULE (for udp) #########################

	if is_enabled_udp; then
		$1 -t mangle -N SSTP_RULE
		$1 -t mangle -N SSTP_LAN_AC
		$1 -t mangle -N SSTP_WAN_AC
		$1 -t mangle -N SSTP_WAN_CHN
		$1 -t mangle -N SSTP_WAN_GFW
		$1 -t mangle -N SSTP_GFW_CHN
		$1 -t mangle -N SSTP_WAN_FW
		$1 -t mangle -N SSTP_WAN_DNS

		$1 -t mangle -A SSTP_RULE -j CONNMARK --restore-mark
		$1 -t mangle -A SSTP_RULE -m mark --mark $ipts_rt_mark -j RETURN
		$1 -t mangle -A SSTP_RULE -m mark --mark 0xff -j RETURN
		$1 -t mangle -A SSTP_RULE -m set --match-set $privaddr_setname dst -j RETURN

		$1 -t mangle -A SSTP_RULE -p udp -m set --match-set $proxyaddr_setname dst -m multiport --dports $proxy_svrport -j RETURN

		$1 -t mangle -A SSTP_RULE -p udp -d $direct_dns_ip --dport 53               -j RETURN
		$1 -t mangle -A SSTP_RULE -p udp -d $remote_dns_ip --dport $remote_dns_port -j MARK --set-mark $ipts_rt_mark
		$1 -t mangle -A SSTP_RULE -p udp -d $remote_dns_ip --dport $remote_dns_port -j RETURN

		$1 -t mangle -A SSTP_RULE -j SSTP_LAN_AC
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_bp src -j RETURN
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_fw src -j SSTP_WAN_FW
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_ac src -j SSTP_WAN_AC
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_gfw src -j SSTP_WAN_GFW
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set sstp_mac_chn src -j SSTP_WAN_CHN
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_bp_setname src -j RETURN
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_fw_setname src -j SSTP_WAN_FW
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_ac_setname src -j SSTP_WAN_AC
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_gfw_setname src -j SSTP_WAN_GFW
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set $sstp_src_chn_setname src -j SSTP_WAN_CHN
		if [ "$LAN_AC_IP" == "2" ] ; then
		$1 -t mangle -A SSTP_LAN_AC -m set ! --match-set $localaddr_setname src -j RETURN
		$1 -t mangle -A SSTP_LAN_AC -m set --match-set $localaddr_setname src -j SSTP_WAN_AC
		else
		$1 -t mangle -A SSTP_LAN_AC -j ${LAN_TARGET:=SSTP_WAN_AC}
		fi
		$1 -t mangle -A SSTP_WAN_AC -j ${MODE_TARGET:=RETURN}
		$1 -t mangle -A SSTP_GFW_CHN -j SSTP_WAN_GFW
		$1 -t mangle -A SSTP_GFW_CHN -j SSTP_WAN_CHN
		$1 -t mangle -A SSTP_GFW_CHN -j RETURN
		[ "$ss_all_udp" == "1" ] && $1 -t mangle -A SSTP_WAN_GFW -p udp -j SSTP_WAN_FW
		$1 -t mangle -A SSTP_WAN_GFW -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
		$1 -t mangle -A SSTP_WAN_GFW -m set --match-set $sstp_dst_fw_setname dst -j SSTP_WAN_FW
		$1 -t mangle -A SSTP_WAN_GFW -m set --match-set $sstp_dst_bp_setname dst -j RETURN
		$1 -t mangle -A SSTP_WAN_GFW -m set --match-set $gfwlist_setname dst -j ${GFWLIST_TARGET:=SSTP_WAN_FW}
		$1 -t mangle -A SSTP_WAN_GFW -j RETURN
		[ "$ss_all_udp" == "1" ] && $1 -t mangle -A SSTP_WAN_CHN -p udp -j SSTP_WAN_FW
		$1 -t mangle -A SSTP_WAN_CHN -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
		$1 -t mangle -A SSTP_WAN_CHN -m set --match-set $sstp_dst_fw_setname dst -j SSTP_WAN_FW
		$1 -t mangle -A SSTP_WAN_CHN -m set --match-set $sstp_dst_bp_setname dst -j RETURN
		$1 -t mangle -A SSTP_WAN_CHN -m set --match-set $chnroute_setname dst -j ${CHN_TARGET:=RETURN}
		$1 -t mangle -A SSTP_WAN_CHN -j ${CHN_WAN_TARGET:=SSTP_WAN_FW}
		$1 -t mangle -A SSTP_WAN_FW -p udp -m multiport --dports $ipts_proxy_dst_port_udp -m conntrack --ctstate NEW -j MARK --set-mark $ipts_rt_mark
		
		$1 -t mangle -A SSTP_WAN_FW -m set --match-set $sstp_dst_dns_fw_setname dst -j SSTP_WAN_DNS
		$1 -t mangle -A SSTP_WAN_DNS -p udp -m multiport --dports 1:65535 -m conntrack --ctstate NEW -j MARK --set-mark $ipts_rt_mark

		$1 -t mangle -A SSTP_RULE -j CONNMARK --save-mark
	fi


	######################### SSTP_OUTPUT/SSTP_PREROUTING #########################

	if is_usrgrp_mode; then
		$1 -t nat -I SSTP_OUTPUT -m owner $(get_usrgrp_args) -j RETURN
		is_enabled_udp && $1 -t mangle -I SSTP_OUTPUT -m owner $(get_usrgrp_args) -j RETURN
	fi
	if is_nonstd_dnsport "$dnsmasq_bind_port"; then
		if [ "$lan_ipaddr" != "$loopback_addr" ] ; then
			$1 -t nat -A SSTP_OUTPUT -p udp -d $lan_ipaddr --dport 53 -j REDIRECT --to-ports $dnsmasq_bind_port
		else
			$1 -t nat -A SSTP_OUTPUT -p udp -d $loopback_addr --dport 53 -j REDIRECT --to-ports $dnsmasq_bind_port
		fi
	fi

	[ "$output_return" != "1" ] && $1 -t nat -A SSTP_OUTPUT -m set --match-set $localaddr_setname src -m set ! --match-set $localaddr_setname dst -p tcp -j SSTP_RULE
	if [ "$output_return" != "1" ] || [ "$output_udp_return" == "1" ] ; then
		is_enabled_udp && $1 -t mangle -A SSTP_OUTPUT -m set --match-set $localaddr_setname src -m set ! --match-set $localaddr_setname dst -p udp -j SSTP_RULE
	fi

	is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -i $ipts_if_lo -m mark ! --mark $ipts_rt_mark -j RETURN

	if is_false "$selfonly"; then
		if is_nonstd_dnsport "$dnsmasq_bind_port"; then
			is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -m set ! --match-set $localaddr_setname src -m set --match-set $localaddr_setname dst -p udp --dport 53 -j RETURN
			$1 -t nat -A SSTP_PREROUTING -m set ! --match-set $localaddr_setname src -m set --match-set $localaddr_setname dst -p udp --dport 53 -j REDIRECT --to-ports $dnsmasq_bind_port
		fi

		$1 -t nat -A SSTP_PREROUTING -m set ! --match-set $localaddr_setname src -m set ! --match-set $localaddr_setname dst -p tcp -j SSTP_RULE
		is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -m set ! --match-set $localaddr_setname src -m set ! --match-set $localaddr_setname dst -p udp -j SSTP_RULE
	fi

	if [ "$lan_ipaddr" != "$loopback_addr" ] ; then
		is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -p udp -m mark --mark $ipts_rt_mark -j TPROXY --on-ip $lan_ipaddr --on-port $proxy_udpport
	else
		is_enabled_udp && $1 -t mangle -A SSTP_PREROUTING -p udp -m mark --mark $ipts_rt_mark -j TPROXY --on-ip $loopback_addr --on-port $proxy_udpport
	fi

	check_snatrule $1
}

start_iptables() {
	resolve_svraddr
	is_true "$ipv4" && start_iptables_pre_rules "iptables"
	is_true "$ipv6" && start_iptables_pre_rules "ip6tables"

	if is_true "$tproxy"; then
		is_true "$ipv4" && start_iptables_tproxy_mode "iptables"
		is_true "$ipv6" && start_iptables_tproxy_mode "ip6tables"
	else
		is_true "$ipv4" && start_iptables_redirect_mode "iptables"
		is_true "$ipv6" && start_iptables_redirect_mode "ip6tables"
	fi
	is_true "$ipv4" && get_wifidognx_output
	is_true "$ipv4" && get_wifidognx
	is_true "$ipv4" && get_wifidognx_mangle
	is_true "$ipv4" && start_iptables_post_rules "iptables"
	check_startdnsredir "iptables"
	wifidognx_output=""
	wifidognx=""
	wifidogn_manglex=""
	is_true "$ipv6" && start_iptables_post_rules "ip6tables"
	is_true "$ipv4" && { is_false "$ipv6" && [ -z "$(ip6tables -vnL INPUT --line-numbers | grep -Ei "udp *dpt:53 *reject")" ] && ip6tables -I INPUT -p udp --dport 53 -j REJECT ; }
	logger -t "【sh_ss_tproxy.sh】" "完成加载 iptables 转发规则...."
}

gen_include() {
echo '#!/bin/bash' >/tmp/firewall.sstp.pdcn
cat <<-CAT >>/tmp/firewall.sstp.pdcn
iptables-restore -n <<-EOF
$(iptables-save | sed  "s/webstr--url/webstr --url/g" | grep -E "SSTP|^\*|^COMMIT" |sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/")
EOF
CAT
return $?
}

get_wifidognx_output() {
	wifidognx_output=""
	wifidogn=`iptables -t nat -L OUTPUT --line-number | grep Outgoing | awk '{print $1}' | awk 'END{print $1}'`  ## Outgoing
	if [ -z "$wifidogn" ] ; then
		wifidogn=`iptables -t nat -L OUTPUT --line-number | grep vserver | awk '{print $1}' | awk 'END{print $1}'`  ## vserver
		if [ -z "$wifidogn" ] ; then
			wifidognx_output=1
		else
			wifidognx_output=`expr $wifidogn + 1`
		fi
	else
		wifidognx_output=`expr $wifidogn + 1`
	fi
}

get_wifidognx() {
	wifidognx=""
	#wifidogn=`iptables -t nat -L PREROUTING --line-number | grep AD_BYBY | awk '{print $1}' | awk 'END{print $1}'`  ## AD_BYBY
	#if [ -z "$wifidogn" ] ; then
		wifidogn=`iptables -t nat -L PREROUTING --line-number | grep Outgoing | awk '{print $1}' | awk 'END{print $1}'`  ## Outgoing
		if [ -z "$wifidogn" ] ; then
			wifidogn=`iptables -t nat -L PREROUTING --line-number | grep vserver | awk '{print $1}' | awk 'END{print $1}'`  ## vserver
			if [ -z "$wifidogn" ] ; then
				wifidognx=1
			else
				wifidognx=`expr $wifidogn + 1`
			fi
		else
			wifidognx=`expr $wifidogn + 1`
		fi
	#else
	#    wifidognx=`expr $wifidogn + 1`
	#fi
	wifidognx=$wifidognx
}

get_wifidognx_mangle() {
	wifidogn_manglex=""
	wifidogn=`iptables -t mangle -L PREROUTING --line-number | grep Outgoing | awk '{print $1}' | awk 'END{print $1}'`  ## Outgoing
		if [ -z "$wifidogn" ] ; then
			wifidogn=`iptables -t mangle -L PREROUTING --line-number | grep UP | awk '{print $1}' | awk 'END{print $1}'`  ## UP
			if [ -z "$wifidogn" ] ; then
				wifidogn_manglex=1
			else
				wifidogn_manglex=`expr $wifidogn + 1`
			fi
		else
			wifidogn_manglex=`expr $wifidogn + 1`
		fi
	wifidogn_manglex=$wifidogn_manglex
}

awk_del_list() {
a_list_conf=$1
b_list_conf=$2
# [a =>> b] 在 b 文件寻找 a 文件的匹配文字并删除，重新生成b文件
if [ -s $a_list_conf ] && [ -s $b_list_conf ] ; then
echo "$(awk '\
NR==FNR{\
  a[$0]++\
}\
NR>FNR{\
  if(($0 in a)) {\
      print ""\
  }\
  else{\
    print $0
  }\
}' $a_list_conf $b_list_conf)" > $b_list_conf
fi
}

start() {
	ss_tproxy_is_started && { stop; status; echo; }
	waiting_network "$opts_ip_for_check_net"
	[ ! -z "$(type -t pre_start)" ] && pre_start

	flush_postrule
	enable_ipforward
	disable_icmpredir
	restore_resolvconf
	start_proxy_proc
	start_dnsserver
	start_iptables
	modify_resolvconf
	update_gfwlist_ipset
	update_chnroute_ipset
	update_wanlanlist_ipset
	update_chnlist_ipset
	update_check_file
	
	update_dnsmasq_file
	
	[ ! -z "$(type -t post_start)" ] && post_start
	delete_unused_iptchains
	gen_include
}

stop() {
	[ ! -z "$(type -t pre_stop)" ] && pre_stop

	restore_resolvconf
	flush_iptables
	#delete_chnroute
	delete_iproute2
	stop_dnsserver
	stop_proxy_proc
	check_postrule

	[ ! -z "$(type -t post_stop)" ] && post_stop
	gen_include
}

status() {
	echo "mode:     $mode"
	tcp_port_is_exists $proxy_tcpport && echo "pxy/tcp:  $(color_green '[running]')" || echo "pxy/tcp:  $(color_red '[stopped]')"
	if is_enabled_udp; then
		udp_port_is_exists $proxy_udpport && echo "pxy/udp:  $(color_green '[running]')" || echo "pxy/udp:  $(color_red '[stopped]')"
	fi
#    process_is_running $status_dnsmasq_pid && echo "dnsmasq:  $(color_green '[running]')" || echo "dnsmasq:  $(color_red '[stopped]')"
#	if is_chnroute_mode; then
#		process_is_running $status_chinadns_pid && echo "chinadns: $(color_green '[running]')" || echo "chinadns: $(color_red '[stopped]')"
#	fi
#	if ! is_enabled_udp; then
#		is_true "$ipv4" && { process_is_running $status_dns2tcp4_pid && echo "dns2tcp4: $(color_green '[running]')" || echo "dns2tcp4: $(color_red '[stopped]')"; }
#		is_true "$ipv6" && { process_is_running $status_dns2tcp6_pid && echo "dns2tcp6: $(color_green '[running]')" || echo "dns2tcp6: $(color_red '[stopped]')"; }
#	fi
}

version() {
	echo "ss-tproxy v4.6"
}

help() {
	cat <<'EOF'
Usage: ss-tproxy <COMMAND> [-x] [name=value...]
COMMAND := {
	start               start ss-tproxy
	stop                stop ss-tproxy
	restart             restart ss-tproxy
	status              status of ss-tproxy
	show-iptables       show iptables rules
	flush-postrule      flush legacy rules
	flush-dnscache      flush dnsmasq cache
	delete-gfwlist      delete ipset@gfwlist
	update-chnlist      update chnlist list
	update-gfwlist      update gfwlist list
	update-chnroute     update chnroute list
	version             show version and exit
	help                show help and exit
}
Specify the -x option for debugging of bash scripts
Specify the name=value to override ss-tproxy configs
Issues or bug report: https://github.com/zfl9/ss-tproxy
See https://github.com/zfl9/ss-tproxy/wiki for more details
EOF
}

main() {
	arguments=""
	optentries=""

	for arg in "$@"; do
		if [ "$arg" = '-x' ]; then
			set -x
		elif [ $(echo "$arg" | grep -c '=') -ne 0 ]; then
			optentries="$optentries ""$arg"
		else
			arguments="$arguments ""$arg"
		fi
	done

	if [ -z "$arguments" ]; then
		echo "$(color_yellow "Missing necessary options")"
		help
		return 0
	fi

	load_config
	check_config

for options in $arguments; do 
	[ "$options" != "h" ] && [ "$options" != "v" ] && logger -t "【sh_ss_tproxy.sh】" "$options"
	case "$options" in
		start)           start; status;;
		stop)            stop; status;;
		restart)              stop; status; echo; start; status;;
		status)          status;;
		show_iptables)           show_iptables;;
		flush-postrule)  flush_postrule;;
		flush-dnscache)  flush_dnscache;;
		delete_gfwlist)  delete_gfwlist;;
		delete_chnroute) delete_chnroute;;
		update-chnlist|update_chnlist)   update_chnlist;;
		update-gfwlist|update_gfwlist)   update_gfwlist;;
		update-chnroute|update_chnroute) update_chnroute;;
		update-chnroute6|update_chnroute6) update_chnroute6;;
		update_chnlist_file)     update_chnlist_file;;
		update_gfwlist_file)     update_gfwlist_file;;
		update_chnroute_file)    update_chnroute_file;;
		update_chnroute_file6)    update_chnroute_file "ipv6";;
		update_chnlist_ipset)    update_chnlist_ipset;;
		update_gfwlist_ipset)    update_gfwlist_ipset;;
		update_chnroute_ipset)   update_chnroute_ipset;;
		update_chnroute_ipset6)   update_chnroute_ipset "ipv6";;
		update_wanlanlist_ipset) update_wanlanlist_ipset;;
		adbyby_cflist_ipset) update_cflist_ipset /tmp/adbyby_host.conf /opt/app/ss_tproxy/dnsmasq.d/r.gfwlist.conf ;;
		resolve_svraddr)         resolve_svraddr;;
		start_iptables)          start_iptables;;
		start_dnsserver_confset) start_dnsserver_confset;;
		v)              version;;
		h|help)              help;;
		*)               echo "$(color_yellow "Unknown option: $arg")"; help; return 1;;
	esac
done
	return 0
}
#set -x
main "$@"
