#!/bin/sh /etc/rc.common

START=99
# local port is defined in $V2_CONF_GENERATE_LUA
SS_REDIR_PORT=7070
SS_REDIR_PIDFILE=/var/run/v2ray-go.pid
PDNSD_LOCAL_PORT=7453
SSRCONF=/etc/v2ray/config.json
V2_CONF_GENERATE_LUA=/etc/v2ray/gen_config.lua
CRON_FILE=/etc/crontabs/root
CONFIG=v2ray
V2RAY_EXEC_PATH=/usr/bin/v2ray/v2ray


# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

	# $covered_subnets, $local_addresses are not required
covered_subnets=`uci get v2ray.@v2ray[0].covered_subnets 2>/dev/null`
local_addresses=`uci get v2ray.@v2ray[0].local_addresses 2>/dev/null`
	# Get LAN settings as default parameters
	[ -f /lib/functions/network.sh ] && . /lib/functions/network.sh
	[ -z "$covered_subnets" ] && network_get_subnet covered_subnets lan
	[ -z "$local_addresses" ] && network_get_ipaddr local_addresses lan
vt_np_ipset="china"  # Must be global variable

__gfwlist_by_mode()
{
	case "$1" in
		V) echo unblock-youku;;
		*) echo china-banned;;
	esac
}



# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

start()
{
  local vt_enabled=`uci get v2ray.@v2ray[0].enabled 2>/dev/null`
  local vt_safe_dns=`uci get v2ray.@v2ray[0].safe_dns 2>/dev/null`
  local vt_safe_dns_port=`uci get v2ray.@v2ray[0].safe_dns_port 2>/dev/null`
  local vt_safe_dns_tcp=`uci get v2ray.@v2ray[0].safe_dns_tcp 2>/dev/null`
  local vt_proxy_mode=`uci get v2ray.@v2ray[0].proxy_mode`
  local vt_server_addr='uci get v2ray.@v2ray[0].address'
  local cron_mode=`uci get v2ray.@v2ray[0].cron_mode 2>/dev/null`
  local vt_gfwlist=`__gfwlist_by_mode $vt_proxy_mode`
  local use_conf_file=`uci get v2ray.@v2ray[0].use_conf_file 2>/dev/null`
  local conf_file_path=`uci get v2ray.@v2ray[0].conf_file_path 2>/dev/null`
  local conf_file_type=`uci get v2ray.@v2ray[0].conf_file_type 2>/dev/null`


	[ -f /etc/init.d/pdnsd ] && /etc/init.d/pdnsd disable 2>/dev/null

	# -----------------------------------------------------------------
	if [ "$vt_enabled" = 0 ]; then
		echo "WARNING: V2Ray is disabled."
		return 1
	fi

	[ -z "$vt_proxy_mode" ] && vt_proxy_mode=M
	[ -z "$vt_method" ] && vt_method=table
	[ -z "$vt_timeout" ] && vt_timeout=60
	case "$vt_proxy_mode" in
		M|S|G)
			[ -z "$vt_safe_dns" ] && vt_safe_dns="8.8.8.8"
			[ -z "$vt_safe_dns_tcp" ] && vt_safe_dns_tcp=1
			;;
	esac
	[ -z "$vt_safe_dns_port" ] && vt_safe_dns_port=53

	# -----------------------------------------------------------------
	###### v2ray ######

	if [ "$use_conf_file" = 0 ]; then
	   	/usr/bin/lua $V2_CONF_GENERATE_LUA $CONFIG $SSRCONF
	    $V2RAY_EXEC_PATH -config=$SSRCONF &
	else
	   $V2RAY_EXEC_PATH -config=$conf_file_path -format=$conf_file_type &
    fi

	sleep 3
	if pidof v2ray>/dev/null; then
	   echo "V2Ray started"
	 else
	   return 1
    fi

	# IPv4 firewall rules
	add_rule

	# -----------------------------------------------------------------
	mkdir -p /var/etc/dnsmasq-go.d
	###### Anti-pollution configuration ######
	if [ -n "$vt_safe_dns" ]; then
		if [ "$vt_safe_dns_tcp" = 1 ]; then
			start_pdnsd "$vt_safe_dns"
			awk -vs="127.0.0.1#$PDNSD_LOCAL_PORT" '!/^$/&&!/^#/{printf("server=/%s/%s\n",$0,s)}' \
				/etc/gfwlist/$vt_gfwlist > /var/etc/dnsmasq-go.d/01-pollution.conf
		else
			awk -vs="$vt_safe_dns#$vt_safe_dns_port" '!/^$/&&!/^#/{printf("server=/%s/%s\n",$0,s)}' \
				/etc/gfwlist/$vt_gfwlist > /var/etc/dnsmasq-go.d/01-pollution.conf
		fi
	else
		echo "WARNING: Not using secure DNS, DNS resolution might be polluted if you are in China."
	fi

	###### dnsmasq-to-ipset configuration ######
	case "$vt_proxy_mode" in
		M|V)
			awk '!/^$/&&!/^#/{printf("ipset=/%s/'"$vt_gfwlist"'\n",$0)}' \
				/etc/gfwlist/$vt_gfwlist > /var/etc/dnsmasq-go.d/02-ipset.conf
			;;
	esac

	# -----------------------------------------------------------------
	###### Restart main 'dnsmasq' service if needed ######
	if ls /var/etc/dnsmasq-go.d/* >/dev/null 2>&1; then
		mkdir -p /tmp/dnsmasq.d
		cat > /tmp/dnsmasq.d/dnsmasq-go.conf <<EOF
conf-dir=/var/etc/dnsmasq-go.d
EOF
		/etc/init.d/dnsmasq restart


	fi
	add_cron
}

stop()
{

	# -----------------------------------------------------------------
	rm -rf /var/etc/dnsmasq-go.d
	if [ -f /tmp/dnsmasq.d/dnsmasq-go.conf ]; then
		rm -f /tmp/dnsmasq.d/dnsmasq-go.conf
		/etc/init.d/dnsmasq restart
	fi

	stop_pdnsd

	# --STOP IPv4 firewall---------------------------------------------------------------
  del_rule

	# -----------------------------------------------------------------
	if [ -f $SS_REDIR_PIDFILE ]; then
		kill -9 `cat $SS_REDIR_PIDFILE`
		rm -f $SS_REDIR_PIDFILE
	fi
	killall -9 v2ray 2>/dev/null
	del_cron
}

restart()
{
	KEEP_GFWLIST=Y
	stop
	start
}

reload()
{
  local vt_enabled=`uci get v2ray.@v2ray[0].enabled 2>/dev/null`
  local vt_server_addr=`uci get v2ray.@v2ray[0].address`
  local vt_safe_dns=`uci get v2ray.@v2ray[0].safe_dns 2>/dev/null`
  local vt_safe_dns_port=`uci get v2ray.@v2ray[0].safe_dns_port 2>/dev/null`
  local vt_safe_dns_tcp=`uci get v2ray.@v2ray[0].safe_dns_tcp 2>/dev/null`
  local vt_proxy_mode=`uci get v2ray.@v2ray[0].proxy_mode`
  local vt_gfwlist=`__gfwlist_by_mode $vt_proxy_mode`
	KEEP_GFWLIST=Y
	del_rule
	add_rule
	if [ "$vt_safe_dns_tcp" = 1 ]; then
    stop_pdnsd
    start_pdnsd
	fi
}

# $1: upstream DNS server
start_pdnsd()
{
	local safe_dns="$1"

	local tcp_dns_list="208.67.222.222, 208.67.220.220"
	[ -n "$safe_dns" ] && tcp_dns_list="$safe_dns,$tcp_dns_list"

	#killall -9 pdnsd 2>/dev/null && sleep 1
	kill -9 $(cat /var/run/pdnsd.pid) >/dev/null 2>&1

	mkdir -p /var/etc /var/pdnsd
	if ! test -f "/var/pdnsd/pdnsd.cache"; then
    dd if=/dev/zero of="/var/pdnsd/pdnsd.cache" bs=1 count=4 2> /dev/null
    chown -R nobody.nogroup /var/pdnsd
  fi

	cat > /var/etc/pdnsd.conf <<EOF
global {
	perm_cache=10240;
	cache_dir="/var/pdnsd";
	pid_file = /var/run/pdnsd.pid;
	run_as="nobody";
	server_ip = 127.0.0.1;
	server_port = $PDNSD_LOCAL_PORT;
	status_ctl = on;
	query_method = tcp_only;
	min_ttl=1h;
	max_ttl=1w;
	timeout=10;
	neg_domain_pol=on;
	proc_limit=2;
	procq_limit=8;
}
server {
	label= "fwxxx";
	ip = $tcp_dns_list;
	port = 53;
	timeout=6;
	uptest=none;
	interval=10m;
	purge_cache=off;
}
EOF

	/usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d

	# Access TCP DNS server through V2Ray tunnel
	if iptables -t nat -N pdnsd_output; then
		iptables -t nat -A pdnsd_output -m set --match-set $vt_np_ipset dst -j RETURN
		iptables -t nat -A pdnsd_output -p tcp -j REDIRECT --to $SS_REDIR_PORT
	fi
	iptables -t nat -I OUTPUT -p tcp --dport 53 -j pdnsd_output
}

stop_pdnsd()
{
	if iptables -t nat -F pdnsd_output 2>/dev/null; then
		while iptables -t nat -D OUTPUT -p tcp --dport 53 -j pdnsd_output 2>/dev/null; do :; done
		iptables -t nat -X pdnsd_output
	fi
	killall -9 pdnsd 2>/dev/null
	rm -rf /var/pdnsd
	rm -f /var/etc/pdnsd.conf
}

add_cron()
{
  sed -i '/up-gfwlist.sh/d' $CRON_FILE
	sed -i '/v2ray_watchdog.log/d' $CRON_FILE
	if [ $cron_mode -eq 1 ]; then
		echo '0 5 * * * /etc/v2ray/up-gfwlist.sh > /tmp/gfwupdate.log 2>&1' >> $CRON_FILE
	fi
	echo '0 */1 * * * /etc/v2ray/v2ray-watchdog >> /tmp/v2ray_watchdog.log 2>&1' >> $CRON_FILE
	echo '0 1 * * 0 echo "" > /tmp/v2ray_watchdog.log' >> $CRON_FILE
	crontab $CRON_FILE
}

del_cron()
{
	sed -i '/up-gfwlist.sh/d' $CRON_FILE
	sed -i '/v2ray_watchdog.log/d' $CRON_FILE
	/etc/init.d/cron restart
}



uci_get_by_name() {
	local ret=$(uci get $CONFIG.$1.$2 2>/dev/null)
	echo ${ret:=$3}
}

uci_get_by_type() {
	local index=0
	if [ -n $4 ]; then
		index=$4
	fi
	local ret=$(uci get $CONFIG.@$1[$index].$2 2>/dev/null)
	echo ${ret:=$3}
}

is_ipv6_address()
{
		echo "$1" | grep -q ":"
}

add_rule()
{
	iptables -t nat -N v2ray_pre
	iptables -t nat -F v2ray_pre
	iptables -t nat -A v2ray_pre -m set --match-set local dst -j RETURN || {
		iptables -t nat -A v2ray_pre -d 10.0.0.0/8 -j RETURN
		iptables -t nat -A v2ray_pre -d 127.0.0.0/8 -j RETURN
		iptables -t nat -A v2ray_pre -d 172.16.0.0/12 -j RETURN
		iptables -t nat -A v2ray_pre -d 192.168.0.0/16 -j RETURN
		iptables -t nat -A v2ray_pre -d 127.0.0.0/8 -j RETURN
		iptables -t nat -A v2ray_pre -d 224.0.0.0/3 -j RETURN
	}

	iptables -t nat -A v2ray_pre -d $vt_server_addr -j RETURN

	iptables -N gameboost -t mangle
	ipset -! create gameuser hash:ip maxelem 65536 2>/dev/null
	ip rule add fwmark 0x01/0x01 table 100
	ip route add local 0.0.0.0/0 dev lo table 100
	iptables -t mangle -A gameboost -p udp -m set --match-set local dst -j RETURN
	iptables -t mangle -A gameboost -p udp -m set --match-set china dst -j RETURN
	iptables -t mangle -A gameboost -p udp --dport 53 -j RETURN
	iptables -t mangle -A gameboost -p udp -j TPROXY --on-port 7070 --tproxy-mark 0x01/0x01
	iptables -t mangle -A PREROUTING -m set --match-set gameuser src -j gameboost

	for i in $(seq 0 100)
	do
		local ip=$(uci_get_by_type acl_rule ipaddr '' $i)
		local mode=$(uci_get_by_type acl_rule filter_mode '' $i)
		case "$mode" in
		disable)
			iptables -t nat -A v2ray_pre -s $ip -j RETURN
			;;
		global)
			iptables -t nat -A v2ray_pre -s $ip -p tcp -j REDIRECT --to $SS_REDIR_PORT
			iptables -t nat -A v2ray_pre -s $ip -j RETURN
			;;
		game)
			iptables -t nat -A v2ray_pre -p tcp -s $ip -m set ! --match-set china dst -j REDIRECT --to $SS_REDIR_PORT
			ipset -! add gameuser $ip
			;;
		esac
	done

	case "$vt_proxy_mode" in
		G) : ;;
		S)
			iptables -t nat -A v2ray_pre -m set --match-set $vt_np_ipset dst -j RETURN
			iptables -t nat -I OUTPUT -p tcp -m multiport --dports 80,443 -m set ! --match-set $vt_np_ipset dst -j REDIRECT --to $SS_REDIR_PORT
			;;
		M)
			ipset -! create $vt_gfwlist hash:ip maxelem 65536 2>/dev/null
      awk '!/^$/&&!/^#/{printf("add vt_gfwlist %s'" "'\n",$0)}' /etc/v2ray/addinip.txt > /tmp/addinip.ipset
      sed -i "s/vt_gfwlist/$vt_gfwlist/g" /tmp/addinip.ipset
      ipset -! restore < /tmp/addinip.ipset
			iptables -t nat -A v2ray_pre -m set ! --match-set $vt_gfwlist dst -j RETURN
			iptables -t nat -A v2ray_pre -m set --match-set $vt_np_ipset dst -j RETURN
			iptables -t nat -I OUTPUT -p tcp -m multiport --dports 80,443 -m set --match-set $vt_gfwlist dst -j REDIRECT --to $SS_REDIR_PORT
			;;
		V)
			vt_np_ipset=""
			ipset -! create $vt_gfwlist hash:ip maxelem 65536 2>/dev/null
			iptables -t nat -A v2ray_pre -m set ! --match-set $vt_gfwlist dst -j RETURN
			;;
	esac
	local subnet
	for subnet in $covered_subnets; do
		iptables -t nat -A v2ray_pre -s $subnet -p tcp -j REDIRECT --to $SS_REDIR_PORT
	done
	iptables -t nat -I PREROUTING -p tcp -j v2ray_pre
}

del_rule()
{
	if iptables -t nat -F v2ray_pre 2>/dev/null; then
		while iptables -t nat -D PREROUTING -p tcp -j v2ray_pre 2>/dev/null; do :; done
		iptables -t nat -X v2ray_pre 2>/dev/null
	fi

	iptables -t nat -D OUTPUT -p tcp -m multiport --dports 80,443 -m set --match-set china-banned dst -j REDIRECT --to $SS_REDIR_PORT 2>/dev/null
	iptables -t nat -D OUTPUT -p tcp -m multiport --dports 80,443 -m set ! --match-set $vt_np_ipset dst -j REDIRECT --to $SS_REDIR_PORT 2>/dev/null

	ip rule del fwmark 0x01/0x01 table 100
	ip route del local 0.0.0.0/0 dev lo table 100
	if iptables -t mangle -F gameboost 2>/dev/null; then
		while iptables -t mangle -D PREROUTING -m set --match-set gameuser src -j gameboost 2>/dev/null; do :; done
		iptables -t mangle -X gameboost 2>/dev/null
	fi

	ipset destroy gameuser 2>/dev/null


	# -----------------------------------------------------------------
	[ "$KEEP_GFWLIST" = Y ] || ipset destroy "$vt_gfwlist" 2>/dev/null
}
