#联网检查
networkCheck() {
	[ ! -f MLBox -o "$networkCheck" != '1' ] && return
	echo -n '正在测试DNS...'
	for ntpip in `./MLBox -timeout=5 -dns="-qtype=A -domain=time.apple.com" | grep -v 'timeout' | grep -E '[1-9][0-9]{0,2}(\.[0-9]{1,3}){3}'`; do break;done
	if [ -n "$ntpip" ]; then
		echo -e "\r✔ DNS联网成功          "
		echo -n '正在测试HTTP...'
		httpIP=`./MLBox -timeout=7 -http="http://182.254.116.116/d?dn=qq.com&clientip=1" 2>&1 | grep -Ev 'timeout|httpGetResponse' | grep -E '[1-9][0-9]{0,2}(\.[0-9]{1,3}){3}'`
		if [ -n "$httpIP" ]; then
			httpIP="${httpIP#*\|}"
			echo -e "\r✔ HTTP联网成功          "
		else
			echo -e "\r✘ HTTP联网失败          "
		fi
		echo -n '正在测试HTTPS...'
		ipInfo=`./MLBox -timeout=7 -http="https://ip.tool.lu/" 2>&1 | grep -Ev 'timeout|httpGetResponse'`
		if echo "$ipInfo" | grep -qi 'IP'; then
			echo -e "\r✔ HTTPS联网成功          "
		else
			httpsResp=`./MLBox -timeout=7 -http="https://ip.cn/dns.html" 2>&1 | grep -Ev 'timeout|httpGetResponse' | grep -E '[1-9][0-9]{0,2}(\.[0-9]{1,3}){3}'`
			if [ -n "$httpsResp" ]; then
				echo -e "\r✔ HTTPS联网成功          "
			else
				echo -e "\r✘ HTTPS联网失败          "
			fi
		fi
		echo -n '正在测试UDP...'
		currentTime=`./MLBox -timeout=5 -ntp="$ntpip" | grep -v 'timeout'`
		echo "$currentTime" | grep -qi 'LI:' && \
			echo -e "\r✔ UDP联网成功          " || \
			echo -e "\r✘ UDP联网失败          "
		echo "✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
		if [ -n "$ipInfo" ]; then
			echo "$ipInfo"
		elif [ -n "$httpIP" ]; then
			echo "当前IP:$httpIP"
		fi
	else
		echo -e "\r✘ DNS联网失败          "
	fi
}

#检查脚本更新
checkUpdate() {
	[ ! -f MLBox -o "$networkCheck" != '1' ] && return
	echo -n '正在获取公告...'
	version='1.1'
	ann=`./MLBox -timeout=7 -http="http://binary.quicknet.cyou/v2rayScript/ann.php?version=$version" 2>/dev/null | grep -Ev 'timeout|httpGetResponse'`
	if [ -n "$ann" ]; then
		if [ -n "$ann" ]; then
			echo "\r$ann"
		else
			echo -e "\r✘ 获取公告失败          "
		fi
	else
		echo -e "\r✘ 获取公告失败          "
	fi
}

#添加开机自启
addAutoStart() {
	if [ ! -d '/data/adb/service.d' ]; then
		echo "必须安装面具root才可以添加开机自启"
		return
	fi
	scriptDir="${0%/*/*}"
	cat >/data/adb/service.d/quickAutoStart.sh <<-EOF
		cd "$scriptDir"
		grep -q "^autoStart='1'" config.ini || exit
		#检测网络
		while "$scriptDir/Core/MLBox" -timeout=4 -http="http://182.254.116.116/d?dn=taobao.com" | grep -q 'network is unreachable'; do sleep 3;done
		#启动防跳
		/system/bin/sh "$scriptDir/Core/Quick" start &>"$scriptDir/autoStart.log"
	EOF
	chmod 777 /data/adb/service.d/quickAutoStart.sh
}

#选择tun处理核心
selectTunCore() {
	[ -n "$tunCore" ] && return
	[ -f 'tun2socks.lock' ] && tunCore='tun2socks' || tunCore='gotun2socks'
}

#检查节点IP
checkNodeContent() {
	{
		kill -9 `cat checkNodeContent.pid`
		#记录原来的节点内容
		oriGlobalNodeContent=`cat ../全局节点/*.ini`
		oriCNNodeContent=`cat ../海内节点/*.ini`
		oriRecords=`cat domainRecords.txt`
	} &>/dev/null
	(while :; do
		#更新节点信息
		if ../工具箱/获取订阅.sh | grep -q '获取节点失败'; then
			#获取节点失败则重新计时
			ret=`./MLBox -cmd="-gid=3004 -nodaemon=true ../工具箱/获取订阅.sh"`
			if echo "$ret" | grep -q '获取节点失败'; then
				sleep $nodeUpdateInterval
				continue
			fi
		fi
		#记录新的节点名称
		newGlobalNodeContent=`cat ../全局节点/*.ini`
		newCNNodeContent=`cat ../海内节点/*.ini`
		#没有新的节点可用, 重新计时
		if [ -z "$newGlobalNodeContent$newCNNodeContent" ]; then
			sleep $nodeUpdateInterval
			continue
		fi
		#如果节点内容不一致则重新启动
		if [ "$oriGlobalNodeContent" != "$newGlobalNodeContent" -o "$oriCNNodeContent" != "$newCNNodeContent" ]; then
			"$PWD/Quick" start
			exit
		fi
		#对比节点的IP
		rm -f 'domainRecords.txt'
		. ./makeConfFile  #生成域名记录
		newRecords=`cat domainRecords.txt`
		for oriRecord in ${oriRecords// /_}; do
			pass=0
			#如果解析不到旧IP就重新执行开启
			for newRecord in ${newRecords// /_}; do
				if [ "$oriRecord" = "$newRecord" ]; then
					pass=1
					break
				fi
			done
			if [ "$pass" != 1 ]; then
				"$PWD/Quick" start
				exit
			fi
		done
		sleep $nodeUpdateInterval
	done &>>/dev/null & echo $! >checkNodeContent.pid)
}

#选择代理核心
selectProxyCore() {
	grep -q 'xtls' v2ray.json 2>/dev/null && proxyCoreName="xray" || proxyCoreName='v2ray'
}

#自动更新核心
autoUpdataCores() {
	for coreInfo in 'MLBox Usage' "${proxyCoreName} Usage"; do
		coreName="${coreInfo%% *}"
		helpFlag="${coreInfo#* }"
		./downloadCore.sh "$mlHost" "$coreName" "$helpFlag"
	done
	if [ ! -f "${tunCore}" -o ! -f "${tunCore}.lock" ]; then
		./downloadCore.sh "$mlHost" "$tunCore" 'Usage'
		if [ ! -f "${tunCore}.lock" ]; then
			[ "$tunCore" = "tun2socks" ] && \
				./downloadCore.sh "$mlHost" "gotun2socks" 'Usage' || \
				./downloadCore.sh "$mlHost" "tun2socks" 'Usage'
		fi
	fi
}

#同时执行iptables和ip6tables
ipts() {
	iptables $@
	ip6tables $@
}

#通过包名得到uid
getPackageUid() {
	packageName="${1}"
	if echo $packageName | grep -q '[A-Za-z]'; then
		packageInfo=`grep -oE "^$packageName ([0-9])+" /data/system/packages.list`
		[ $? != 0 ] && return 1
		echo "${packageInfo#* }"
	else
		echo "$1"
	fi
}

#应用放行
appsAllow() {
	[ -n "$1" ] && appProtocol="-p $1" || appProtocol=''
	apps="$2"
	for app in $apps; do
		uid=`getPackageUid $app` || continue
		uid="${uid%_*}"
		ipts -t mangle -I TUN_OUTPUT $appProtocol -m owner --uid $uid -j ACCEPT
		[ "$app" != "$uid" ] && \
			grep -q "uid n=\"999${uid%_*}\"" '/data/system/appops.xml' && \
			ipts -t mangle -I TUN_OUTPUT $appProtocol -m owner --uid 999${uid} -j ACCEPT
	done
}

#放行
allowService() {
	#IP放行
	for ip in $allowIPs; do
		ipts -t mangle -I TUN_OUTPUT -d $ip -j ACCEPT
		ipts -t mangle -I TUN_PREROUTING -d $ip -j ACCEPT
	done 2>/dev/null  #ipv6跟ipv4不兼容会提示错误
	#本地UDP放行
	appsAllow udp "$localUdpAllowApps"
	#本地TCP放行
	appsAllow tcp "$localTcpAllowApps"
	#本地全局放行
	appsAllow '' "$localAllowApps"
	#共享全局放行
	if [ "$shareAllow" = '1' ]; then
		ipts -t mangle -F TUN_PREROUTING
	else
		#共享UDP放行
		[ "$shareAllowUdp" = '1' ] && \
			ipts -t mangle -I TUN_PREROUTING -p udp -j ACCEPT
		#共享TCP放行
		[ "$shareAllowTcp" = '1' ] && \
			ipts -t mangle -I TUN_PREROUTING -p tcp -j ACCEPT
	fi
}

#配置主要ip[6]tables
set_iptables() {
	ipts -N TUN_OUTPUT 2>/dev/null
	ipts -N TUN_FORWARD 2>/dev/null
	ipts -t mangle -N TUN_OUTPUT 2>/dev/null
	ipts -t mangle -N TUN_PREROUTING 2>/dev/null
	ipts -t mangle -A TUN_OUTPUT -p udp --dport 67:68 -j ACCEPT #放行dhcp
	#WiFi代理规则
	[ "$allowWifi" = '1' ] && \
		ipts -t mangle -A TUN_OUTPUT -o wlan+ -j ACCEPT || \
		#标记WiFi(WiFi的内网可能是192.168/16和fe80::/10)的DNS
		ipts -t mangle -A TUN_OUTPUT -o wlan+ -p 17 --dport 53 -j  MARK --set-xmark 999
	##本机规则
	ipts -t mangle -A TUN_OUTPUT -o tun+ -j ACCEPT
	#内核禁网
	if [ "$kernelOpt" = 'deny' ]; then
		ipts -t mangle -A TUN_OUTPUT -m owner ! --uid 0-999999999 -j DROP || \
			ipts -t mangle -A TUN_OUTPUT -m owner ! --uid 0-99999 -j DROP  #部分设备uid最大值为99999
	fi 2>/dev/null
	if [ -n "$proxyApps" ]; then
		for app in $proxyApps; do
			uid=`getPackageUid $app` || continue
			ipts -t mangle -I TUN_OUTPUT -m owner --uid $uid -j MARK --set-xmark 999
			[ "$app" != "$uid" ] && \
				grep -q "uid n=\"999${uid%_*}\"" '/data/system/appops.xml' && \
				ipts -t mangle -I TUN_OUTPUT -m owner --uid 999${uid} -j MARK --set-xmark 999
		done
	else
		ipts -t mangle -A TUN_OUTPUT -j MARK --set-xmark 999
	fi
	ipts -A TUN_OUTPUT -m mark --mark 999 -j ACCEPT
	##共享规则
	iptables -t mangle -A TUN_PREROUTING -d 192.168/16 ! -p udp -j ACCEPT
	iptables -t mangle -A TUN_PREROUTING -d 192.168/16 -p udp ! --dport 53 -j ACCEPT
	ipts -t mangle -A TUN_PREROUTING -j MARK --set-xmark 999
	#共享的数据包在FORWARD放行
	#ipts -A TUN_FORWARD -i tun+ -j ACCEPT
	ipts -A TUN_FORWARD -m mark --mark 999 -j ACCEPT
	##主链跳转到防跳规则
	ipts -I OUTPUT -g TUN_OUTPUT
	ipts -I FORWARD -g TUN_FORWARD
	ipts -t mangle -I PREROUTING ! -i tun+ -g TUN_PREROUTING
	if [ "$onlyProxyShare" != '1' ]; then
		iptables -t mangle -I OUTPUT ! -o lo ! -d 192.168/16 -m owner ! --gid 3004 -g TUN_OUTPUT
		ip6tables -t mangle -I OUTPUT ! -o lo ! -d fe80::/10 -m owner ! --gid 3004 -g TUN_OUTPUT
	fi
	#不代理IPv6则清空ip6tables规则
	if [ "$ipv6Opt" != 'proxy' ]; then
		ip6tables -t mangle -D PREROUTING ! -i tun+ -g TUN_PREROUTING
		ip6tables -t mangle -D OUTPUT ! -o lo ! -d fe80::/10 -m owner ! --gid 3004 -g TUN_OUTPUT
	fi 2>/dev/null
}
#ip路由
ip_route() {
	while :; do
		ret=`ip addr add 10.0.0.1/24 dev tunDev 2>&1`
		[ "$?" -eq '0' ] && break
		echo "$ret" | grep -iq 'file exists' && break
		sleep 1
	done
	ip link set tunDev up qlen 3000

	ip rule add fwmark 999 lookup 101 pref 99  #代理
	ip route add default dev tunDev table 101
	if [ "${ipv6Opt:0:4}" = 'deny' ]; then  #禁网ipv6
		ip -6 rule add not iif lo unreachable pref 99
	elif [ "$ipv6Opt" = 'proxy' ]; then  #代理ipv6
		while :; do
			ret=`ip -6 addr add fec0::1/64 dev tunDev 2>&1`
			[ "$?" -eq '0' ] && break
			echo "$ret" | grep -iq 'file exists' && break
			sleep 1
		done
		ip -6 rule add fwmark 999 lookup 101 pref 99  #代理
		ip -6 route add default dev tunDev table 101
	fi
}

#创建tun设备
createTun() {
	echo 1 > /proc/sys/net/ipv4/ip_forward
	[ ! -e "/dev/net/tun" ] && mkdir -p /dev/net && ln -s /dev/tun /dev/net/tun
}

#状态检查
statusCheck() {
	echo "✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
	selectProxyCore  #选择代理核心
	selectTunCore  #选择tun核心
	ret=`./MLBox -status="$proxyCoreName $tunCore"`
	echo "$ret"
	echo "✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
	echo "$ret" | grep -q "已运行 $proxyCoreName" || return
	[ "$deny_ad" = '1' ] && echo '● 已开启禁网广告'
	case "$kernelOpt" in 
		'deny') echo '● 已开启禁网内核';;
		'allow') echo '⊙ 已开启放行内核';;
	esac
	case "$ipv6Opt" in 
		'deny') echo '● 已开启禁网ipv6';;
		'allow') echo '⊙ 已开启放行ipv6'
	esac
	[ -n "$nodeUpdateInterval" ] && echo '● 已开启自动检查节点IP'
	if [ "$shareAllow" = '1' ]; then
		echo '● 已开启共享全局放行'
	elif [ "$shareAllowUdp" = '1' ]; then
		echo '● 已开启共享UDP放行'
	elif [ "$onlyProxyShare" = '1' ]; then
		echo '● 已开启只代理共享, 本机数据将会放行'
	fi
	[ -n "$(ls 海内节点 2>/dev/null)" ] && echo '● 已开启海内外分流'
	if [ -n "$proxyApps" ]; then
		echo '● 代理应用列表:'
		for app in $proxyApps; do echo "    $app"; done
	fi
	if [ -n "$localAllowApps" ]; then
		echo '● 全局放行应用:'
		for app in $localAllowApps; do echo "    $app"; done
	fi
	if [ -n "$localUdpAllowApps" ]; then
		echo '● UDP放行应用:'
		for app in $localUdpAllowApps; do echo "    $app"; done
	fi
	echo "✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
	[ "$onlyProxyShare" = '1' ] || networkCheck
	echo "✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
	checkUpdate
	echo "✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
}

#关闭脚本
clearServer() {
	#关闭程序
	./MLBox -kill="xray v2ray tun2socks gotun2socks"
	kill -9 `cat checkNodeContent.pid 2>/dev/null` 2>/dev/null
	#清理ip路由规则
	{
		while ip rule del pref 99; do :;done
		while ip -6 rule del pref 99; do :;done
		ipts -F TUN_OUTPUT
		ipts -F TUN_FORWARD
		ipts -t mangle -F TUN_PREROUTING
		ipts -t mangle -F TUN_OUTPUT
		while ipts -D OUTPUT -g TUN_OUTPUT; do :;done
		while ipts -D FORWARD -g TUN_FORWARD; do :;done
		while ipts -t mangle -D PREROUTING ! -i tun+ -g TUN_PREROUTING; do :;done
		while iptables -t mangle -D OUTPUT ! -o lo ! -d 192.168/16 -m owner ! --gid 3004 -g TUN_OUTPUT; do :;done
		while ip6tables -t mangle -D OUTPUT ! -o lo ! -d fe80::/10 -m owner ! --gid 3004 -g TUN_OUTPUT; do :;done
	} 2>/dev/null
}

#启动脚本
startServer() {
	createTun  #创建tun
	clearServer  #清理规则
	. ./makeConfFile  #生成配置
	selectProxyCore  #选择代理核心
	selectTunCore  #选择tun核心
	autoUpdataCores  #自动更新核心
	set_iptables  #设置ip[6]tables代理规则
	allowService  #执行放行代码
	ulimit -n 1048576
	if [ "$tunCore" = 'tun2socks' ]; then
		./MLBox -cmd="-gid=3004 ./tun2socks --tundev tunDev --netif-ipaddr 10.0.0.2 --netif-ip6addr fc00::1 --netif-netmask 255.255.255.0 --socks-server-addr 127.0.0.1:10800 --enable-udprelay --loglevel 0"
	else
		./MLBox -cmd="-gid=3004 ./gotun2socks -loglevel silent -device tunDev -proxy 127.0.0.1:10800 -mtu 1500 -udp-timeout 30s"
	fi
	./MLBox -cmd="-gid=3004 ./${proxyCoreName} run -config v2ray.json" >/dev/null
	##等待核心初始化完成
	sleep 1
	count=0
	while ./MLBox -timeout='1' -http='http://127.0.0.1:10800'|grep -q 'connection refused' && [ "$count" -le '15' ]; do
		./MLBox -status="v2ray" | grep -q '停止' && break
		echo '等待核心初始化完成...'
		count=$((count + 1))
		sleep 1
	done
	ip_route  #ip路由
	addAutoStart  #添加开机自启
}

#ip[6]tables命令获取锁失败则重新执行
aliasIptables() {
	iptables_path=`type iptables 2>/dev/null | grep -o '/.*'`
	ip6tables_path=`type ip6tables 2>/dev/null | grep -o '/.*'`
	if iptables --help | grep -q "\-w"; then
		iptables() { "${iptables_path:=/system/bin/iptables}" -w $@; }
		ip6tables() { "${ip6tables_path:=/system/bin/ip6tables}" -w $@; }
	else
		iptables() {
			"${iptables_path:=/system/bin/iptables}" $@
			[ "$?" = '4' ] && iptables $@
		}
		ip6tables() {
			"${ip6tables_path:=/system/bin/ip6tables}" $@
			[ "$?" = '4' ] && ip6tables $@
		}
	fi
}

init() {
	cd "${1%/*}"
	chmod 777 *
	eval "`grep -v '^\;' ../config.ini`"  #ini文件;开头是注释
}

#脚本入口
main() {
	init "$1"
	aliasIptables
	case "$2" in
		'stop')
			clearServer
			statusCheck
		;;
		'start')
			echo "✄┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄"
			startServer
			statusCheck
			[ -n "$nodeUpdateInterval" ] && checkNodeContent  #检查节点信息
		;;
		'status')
			statusCheck
		;;
	esac
}

main "$0" "$1" 2>&1
