#!/bin/sh
. /lib/functions/network.sh
vpname=hninpop
base_url=https://cpe.hnsmmg.com

# 检查pid
_checkpid(){
	pid=`echo $$`
	pname=`echo $0`
	mypidfile=/tmp/hninpop.pid
	if test -f "$mypidfile";then
		expid=`cat $mypidfile`
		if grep $pname /proc/`cat $mypidfile`/cmdline > /dev/null 2>&1 ;then
			echo "The process $pname is already exists ! pid:$expid."
			exit 0
		fi		
	fi
	echo $pid > $mypidfile
}

# 读取hninpop配置的函数
config_get() {
    local option=$1
    local value
    value=$(uci -q get hninpop.@default[0]."$option")
    echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
}


# 在线获取连接信息
_get_connect_info() {
	# 获取wireguard配置
	connect_info=$(curl --connect-timeout 3 --silent --location "$base_url/api/v1/user" \
		--header 'Content-Type: application/json' \
		--data '{
			"account": "'"$username"'",
			"password": "'"$password"'"
			'"$(if [ "$testmode" = "1" ]; then echo ',"mode":"test"'; fi)"'
		}')


	# 判断是否为json格式
	if ! echo "$connect_info" | jq . >/dev/null 2>&1; then
		echo "Error: Invalid JSON format."
		exit 1
	fi
	
	# 返回连接信息
	echo $connect_info
}

# 检查配置并发起连接
_check_config(){
	# 读取配置项
	testmode=$(config_get "testmode")

	# 读取配置项
	enable=$(config_get "enable")
	username=$(config_get "username")
	password=$(config_get "password")

	# 如果enable为1，且用户名和密码不为空，则执行连接VPN的操作
	if [ "$enable" = "1" ] && [ -n "$username" ] && [ -n "$password" ]; then
        connect_info=$(_get_connect_info)

		# 连接vpn
		_connectvpn
	else
		_deletevpn
		return
	fi
}

# 删除VPN
_deletevpn(){
	# 条件不满足，删除vpn接口
	iptables -t nat -D PREROUTING -i br-lan -p udp --dport 53 -j DNAT --to 192.168.10.1 -m comment --comment "DNS-Hijack" > /dev/null 2>&1
	iptables -t nat -D PREROUTING -i br-lan -p tcp --dport 53 -j DNAT --to 192.168.10.1 -m comment --comment "DNS-Hijack" > /dev/null 2>&1
	uci del network.$vpname > /dev/null 2>&1
	uci commit network
	ip link del $vpname > /dev/null 2>&1
}
# 连接VPN
_connectvpn() {
	# 加载 jshn.sh
	. /usr/share/libubox/jshn.sh

	# 加载 JSON 数据
	json_load "$connect_info"

	# 获取 code 值
	json_get_var code code

	# 判断是否成功
	if [ "$code" = "200" ]; then

		# 获取私钥和私有IP
		json_get_var private_key private_key
		json_get_var private_ip private_ip
		json_get_var login_status login_status
		
		# 如果登录状态不为0，则删除VPN接口并退出
		if [ "$login_status" != "0" ]; then
			echo "Error: Login status is not 0, disconnecting."
			uci set hninpop.@default[0].login_status="$login_status"
			uci commit hninpop
			# 删除VPN接口
			_deletevpn
			return
		else
			# 设置登录状态为0
			uci set hninpop.@default[0].login_status="0"
			uci commit hninpop
		fi
		# 进入 server 数组并选择第一个元素（索引从1开始）
		json_select server
		# json_select 1
		
		# 获取 server 中的相关信息
		json_get_var ip ip
		json_get_var port port
		json_get_var dns_server dns_server
		json_get_var public_key public_key
		
		# # 输出相关信息
		# echo $ip $port $dns_server $public_key 
		# echo $private_key $private_ip
	fi

	# 如果code不为200，则输出错误信息，并停止
	if [ "$code" != "200" ]; then
		ipmode=$(config_get "ipmode")
		if [ "$ipmode" != "1" ]; then
			_deletevpn
		fi
		echo "Error: $code"
		exit 1
	fi

	# 添加wireguard协议的接口hninpop
	uci set network.$vpname=interface
	uci set network.$vpname.proto='wireguard'
	
	local_private_key=$(uci -q get network.$vpname.private_key)
	if [ "$local_private_key" != "$private_key" ]; then
		uci set network.$vpname.private_key=$private_key
		uci set hninpop.@default[0].update_info=1
	fi

	# 检查接口是否已经存在并配置了IP地址
	local_ip=$(uci -q get network.$vpname.addresses)
	if [ -z "$local_ip" ]; then
		echo "Add IP address to $vpname"
		uci add_list network.$vpname.addresses=$private_ip'/32'
		uci set hninpop.@default[0].update_info=1
	else
		if [ "$local_ip" != "$private_ip/32" ]; then
			uci set network.$vpname.addresses=$private_ip'/32'
			uci set hninpop.@default[0].update_info=1
		fi
	fi

	uci set network.$vpname.defaultroute='0'
	uci set network.$vpname.peerdns='0'
	uci set network.$vpname.delegate='0'
	uci commit network.$vpname


	# 添加hninpop接口到firewall
	FIREWALL=$(uci -q get firewall.@zone[1].network)
	echo $FIREWALL|grep $vpname >/dev/null
	if [ "$?" != "0" ];then
		echo " Add $vpname to Firewall"
		uci set firewall.@zone[1].network="$FIREWALL $vpname"
		uci commit firewall
	fi

	# 给接口hninpop添加peer
	uci show network|grep wireguard_$vpname > /dev/null
	if [ "$?" != "0" ];then
		uci add network wireguard_$vpname # =cfg09f3aa
		uci set network.@wireguard_$vpname[-1].description=$username
		uci set network.@wireguard_$vpname[-1].public_key=$public_key
		uci add_list network.@wireguard_$vpname[-1].allowed_ips='0.0.0.0/0'
		uci set network.@wireguard_$vpname[-1].endpoint_host=$ip
		uci set network.@wireguard_$vpname[-1].endpoint_port=$port
		uci set network.@wireguard_$vpname[-1].persistent_keepalive='25'
		uci commit network
		uci set hninpop.@default[0].update_info=1
	else
		local_peer_public_key=$(uci -q get network.@wireguard_$vpname[-1].public_key)
		local_peer_ip=$(uci -q get network.@wireguard_$vpname[-1].endpoint_host)
		local_peer_port=$(uci -q get network.@wireguard_$vpname[-1].endpoint_port)
		if [ "$local_peer_public_key" != "$public_key" ] || [ "$local_peer_ip" != "$ip" ] || [ "$local_peer_port" != "$port" ]; then
			uci set network.@wireguard_$vpname[-1].description=$username
			uci set network.@wireguard_$vpname[-1].public_key=$public_key
			uci set network.@wireguard_$vpname[-1].endpoint_host=$ip
			uci set network.@wireguard_$vpname[-1].endpoint_port=$port
			uci commit network
			uci set hninpop.@default[0].update_info=1
		fi
	fi

	# 添加服务器IP到路由表。
	ip route add $ip via $(_getwan) metric 100 > /dev/null 2>&1

	# 如果ifconfig hninpop不存在，则执行ifup hninpop
	ifconfig $vpname > /dev/null 2>&1
	if [ "$?" = "1" ];then
		ifup $vpname
	fi

	# 更新配置
	vpn_update_info=$(config_get "update_info")
	if [ "$vpn_update_info" = "1" ]; then
		ifup $vpname
		uci set hninpop.@default[0].update_info=0
		uci commit hninpop
	fi

	# ifup $vpname
	_checkroute
	_checkdns
}

# 设置路由表
_checkroute(){
	# 检查vpn接口流量是否正常
	vpnstatus=$(_checkvpnstatus)
	# 如果vpnstatus = 1 ， vpn接口流量不正常，则删除vpn接口路由表
	if [ "$vpnstatus" = "1" ];then
		ipmode=$(config_get "ipmode")
		if [ "$ipmode" != "1" ]; then
			# 删除vpn接口路由表
			ip route del 0.0.0.0/1 dev $vpname > /dev/null 2>&1
			ip route del 128.0.0.0/1 dev $vpname > /dev/null 2>&1
			# 删除quagga配置
			/etc/init.d/quagga stop > /dev/null 2>&1
		fi
	else
		# 获取网关以及路由表数量
		. /lib/functions/network.sh
		network_find_wan NET_IF
		network_get_gateway NET_GATEWAY "${NET_IF}"
		routenum=`ip route|grep $NET_GATEWAY|wc -l`

		#获取tunnelall配置
		tunnelall=$(config_get "tunnelall")
		if [ "$tunnelall" != "1" ];then
			# 分流模式，启动quagga
			if [ "$routenum" -lt "5000" ];then
				sed 's/^/ip route &/g' /etc/chnroute > /etc/quagga/zebra.conf
				sed -i "s/$/& $NET_GATEWAY/g" /etc/quagga/zebra.conf
				echo "" >> /etc/quagga/zebra.conf
				/etc/init.d/quagga restart > /dev/null 2>&1
			fi

		else
			# 全局模式，关闭quagga
			if [ "$routenum" -gt "5000" ];then
				/etc/init.d/quagga stop > /dev/null 2>&1
			fi
		fi

		#设置路由表，全部流量走vpn出口
		ip route|grep 0.0.0.0/1|grep $vpname >/dev/null 2>&1
		if [ "$?" = "1" ];then
			ip route add 0.0.0.0/1 dev $vpname
			ip route add 128.0.0.0/1 dev $vpname
		fi
	fi
}


# 检查vpn接口流量是否正常
_checkvpnstatus(){

	#获取vpn接口流量
	vpntraffic1=`wg show $vpname transfer | grep $public_key|awk '{print $2}'`

	# 使用接口ping一下8.8.8.8
	ping -q -W 2 -4 -c 4 8.8.8.8 -I $vpname > /dev/null 2>&1
	# 获取vpn接口流量
	vpntraffic2=`wg show $vpname transfer | grep $public_key|awk '{print $2}'`

	# 如果vpn接口流量没有增加，则删除vpn接口路由表
	if [ "$vpntraffic1" = "$vpntraffic2" ];then
		echo 1
	else
		echo 0
	fi

}

_checkdns(){
	# 检查vpn接口流量是否正常
	vpnstatus=$(_checkvpnstatus)

	# 如果vpn接口流量正常，则检查dns是否正常
	if [ "$vpnstatus" = "0" ];then
		local_resolv=$(nslookup www.google.com localhost | awk '/^Address 1: / {print $3}')
		remote_resolv=$(nslookup www.google.com 1.1.1.3 | awk '/^Address 1: / {print $3}')

		# 如果本地dns和远程dns不一致，则修改dnsmasq配置
		if [ "$local_resolv" != "$remote_resolv" ];then

			# 生成dnsmasq配置文件
			if [ ! -f /tmp/dnsmasq.conf ];then
				cat>/tmp/dnsmasq.conf<<EOF
no-resolv
all-servers
server=180.76.76.76,0
server=114.114.114.114,0
server=1.1.1.3,1
server=1.0.0.3,1
chnroutes-file=/etc/chnroute

EOF
			fi
			
			tmp_md5=`md5sum /tmp/dnsmasq.conf|awk '{print $1}'`
			dns_md5=`md5sum /etc/dnsmasq.conf|awk '{print $1}'`

			if [ "$tmp_md5" != "$dns_md5" ];then
				cp /tmp/dnsmasq.conf /etc/dnsmasq.conf -f
			fi

			# 重启dnsmasq
			/etc/init.d/dnsmasq restart
		fi
	fi
	_dnshijack
}

_dnshijack(){
	hijack_status=$(iptables -t nat --list|grep DNS-Hijack|wc -l)
	# 如果hijack_status小于2，则添加hijack规则
	if [ "$hijack_status" -lt "2" ];then
		iptables -t nat -D PREROUTING -i br-lan -p udp --dport 53 -j DNAT --to 192.168.10.1 -m comment --comment "DNS-Hijack" > /dev/null 2>&1
		iptables -t nat -D PREROUTING -i br-lan -p tcp --dport 53 -j DNAT --to 192.168.10.1 -m comment --comment "DNS-Hijack" > /dev/null 2>&1
		iptables -t nat -A PREROUTING -i br-lan -p udp --dport 53 -j DNAT --to 192.168.10.1 -m comment --comment "DNS-Hijack"
		iptables -t nat -A PREROUTING -i br-lan -p tcp --dport 53 -j DNAT --to 192.168.10.1 -m comment --comment "DNS-Hijack"
	fi
}

_checkupdate(){
	# 自动更新软件版本
	# base_url=https://cpe.hnsmmg.com
	echo "check update"
	# 检查/tmp 目录下是否存在/tmp/hninpop_update.lock文件
	if [ ! -f /tmp/hninpop_update.lock ];then
		# 删除update.tar.gz
		rm -f /tmp/update.tar.gz
		# 删除update.sh
		rm -f /tmp/update.sh
		# 下载update.tar.gz
		wget -O /tmp/update.tar.gz $base_url/software/update.tar.gz
		if [ -f /tmp/update.tar.gz ] && [ -s /tmp/update.tar.gz ];then
			# 解压update.tar.gz
			tar -zxvf /tmp/update.tar.gz -C /tmp/
			# 判断解压是否成功
			if [ "$?" = "0" ];then
				# 判断是否存在update.sh
				if [ -f /tmp/update.sh ];then
					# 执行update.sh,并创建一个Lock文件锁定update，防止重复执行
					touch /tmp/hninpop_update.lock
					sh /tmp/update.sh
					# 等待执行完毕后删除update.sh 和 update.tar.gz
					rm -f /tmp/update.sh
					rm -f /tmp/update.tar.gz
				fi
			fi
		fi
	fi
}

_checksysupdate(){
	echo "check sys update"
	if [ ! -f /tmp/sys_update.lock ];then
		rm -f /tmp/sys_update.tar.gz
		rm -f /tmp/sys_update.sh
		wget -O /tmp/sys_update.tar.gz $base_url/software/sys_update.tar.gz
		if [ -f /tmp/sys_update.tar.gz ] && [ -s /tmp/sys_update.tar.gz ];then
			tar -zxvf /tmp/sys_update.tar.gz -C /tmp/
			if [ "$?" = "0" ];then
				if [ -f /tmp/sys_update.sh ];then
					touch /tmp/sys_update.lock
					sh /tmp/sys_update.sh
					rm -f /tmp/sys_update.sh
					rm -f /tmp/sys_update.tar.gz
				fi
			fi
		fi
	fi
}

_getwan(){
	. /lib/functions/network.sh
	network_find_wan NET_IF
	network_get_gateway NET_GATEWAY "${NET_IF}"
	echo $NET_GATEWAY
}

_start(){
	_checkpid
	while true;do
		_checkupdate
		_checksysupdate
		_check_config
	sleep 30
	done
}

_stop(){
	/etc/init.d/hninpop stop
}

_check_user(){
	# 检查用户输入的账号密码信息是否正确
	username=$(config_get "username")
	# 如果用户名为空，则提示用户输入用户名
	if [ -z "$username" ]; then
		echo "请输入用户名."
		uci set hninpop.@default[0].description="请输入用户名."
		uci commit hninpop
		_deletevpn
		exit 1
	fi
	password=$(config_get "password")
	# 如果密码为空，则提示用户输入密码
	if [ -z "$password" ]; then
		echo "请输入密码."
		uci set hninpop.@default[0].description="请输入密码."
		uci commit hninpop
		_deletevpn
		exit 1
	fi
	# 如果用户名和密码都不为空，则使用curl post到服务器验证
	connect_info=$(curl --connect-timeout 3 --silent --location "$base_url/api/v1/user" \
	--header 'Content-Type: application/json' \
	--data '{
		"account": "'"$username"'",
		"password": "'"$password"'"
	}')
	# 判断是否为json格式
	if ! echo "$connect_info" | jq . >/dev/null 2>&1; then
		echo "Error: Invalid JSON format."
		uci set hninpop.@default[0].description="连接信息获取失败."
		uci commit hninpop
		exit 1
	fi

	# 加载 jshn.sh
	. /usr/share/libubox/jshn.sh
	# 加载 JSON 数据
	json_load "$connect_info"

	json_get_var code code
	json_get_var msg msg
	json_get_var expired_time expired_time
	expired_time=$(date -d @$expired_time "+%Y-%m-%d %H:%M:%S")

	# 根据code值返回不同的信息
	case "$code" in
		200)
			echo "到期时间：$expired_time"
			uci set hninpop.@default[0].description="到期时间：$expired_time"
			uci commit hninpop
			;;
		*)
			echo "$msg"
			uci set hninpop.@default[0].description="$msg"
			uci commit hninpop
			_deletevpn
			;;
	esac
}

action=$1
case "$action" in
	stop) 
		_stop
		;;
	getwan) 
		_getwan
		;;
	check_user)
		_check_user
		;;
	*)
		_start
		;;
esac

