#!/bin/sh
#
#execute by /lib/firewall.sysapi.loader when system firewall start/reload
#
#TODO: hack fw3 to support create custom chain and target to chain
#
#TODO: hack fw3 to using -m u32
#
#TODO: change all rules in uci and fw3 reload
#
#TODO: make macfilter rules stable
#
. /lib/lib.scripthelper.sh
#
. /lib/functions.sh

export ctlop="$1"
export addop="$2"
export exitcode=0

if [ -z "$ctlop" ]
	then
	elog "WARNING: Usage: $0 <index> [add args]"
	exit 1
fi

errcount(){
	local errcode="$1"
	test -z "$errcode" && return 0
	test "$errcode" -ne 0 && let exitcode=$exitcode+1
	return 0
}

proclock(){
	local needlan
	needlan="$1"
	LANIPMASK="$(getlanipmask)"
	if [ "$needlan" = 'needlan' -a -z "$LANIPMASK" ]
		then
		dlog "INFO: bypass for lan ip/netmask no exist."
		exit 0
	fi
	#
	dlog "INFO: LANIPMASK: $LANIPMASK"
	#
	checkproclock 30 replaceproc
	#check lock, return 0 for no locked, 1 for locked
	if [ $? -ne 0 ]
		then
		elog "ERROR: executing $ALLARGS exited, waiting for proc lock failed after 30 seconds, current locked pid: $(getlockedprocpid)"
		exit 1
	fi
	setproclock
}

#prepare_doit(){
#	#delegate_postrouting of mangle for landownloadtraffic
#	iptnewchain "-N delegate_postrouting -t mangle"
#	errcount $?
#	iptables -L POSTROUTING -t mangle --line-numbers 2>/dev/null | grep '1 ' | grep -q 'delegate_postrouting'
#	if [ $? -eq 0 ]
#		then
#		return 0
#	fi
#	iptremoverule "-D POSTROUTING -t mangle -j delegate_postrouting"
#	iptexec "iptables -I POSTROUTING -t mangle -j delegate_postrouting"
#	errcount $?
#}


webinitrdr_disable(){
	local force="$1"
	local initMark="$(uci get xiaoqiang.common.INITTED 2>/dev/null)"
	if [ "$initMark" != 'YES' -o "$force" = 'force' ]
		then
		touch /etc/config/xiaoqiang 2>/dev/null
		errcount $?
		uci set xiaoqiang.common='core' && uci set xiaoqiang.common.INITTED='YES' && uci commit xiaoqiang
		errcount $?
		if [ "$initMark" = 'YES' -a "$force" = 'force' ]
			then
			dlog "INFO: force remove redirect rules and restart services."
		else
			dlog "INFO: remove redirect rules and restart services."
		fi
		iptremoverule "-D $HTTPRDR_RULE"
		iptremoverule "-D $DNSRDR_RULE"
		test -x /etc/init.d/dnsmasq && dlog "INFO: restart dnsmasq for webinitrdr." && /etc/init.d/dnsmasq restart &
	else
		dlog "INFO: disable skipped for already initialed."
	fi
	sync 2>/dev/null
	return 0
}

webinitrdr_doit(){
		#
		#if [ "$(nvram get model 2>/dev/null)" = "R1CM" ];then
		#	dlog "INFO: R1CM platform ,disable webinitrdr."
		#	return 0
		#fi
		NGINXWEBINITPORT=8098
		DNSWEBINITPORT=53
		#
		HTTPRDR_RULE="prerouting_lan_rule -t nat -p tcp --dport 80 -m comment --comment HTTPWEBINITRDR -j REDIRECT --to-ports $NGINXWEBINITPORT"
		DNSRDR_RULE="prerouting_lan_rule -t nat -p udp --dport 53 -m comment --comment DNSWEBINITRDR -j REDIRECT --to-ports $DNSWEBINITPORT"
		#
		test -z "$addop" && addop='on'
		if [ "$addop" = 'off' -o "$addop" = 'stop' ]
			then
			#
			proclock
			#
			webinitrdr_disable force
			dlog "INFO: webinitrdr manual disabled."
			return 0
		fi
		#
		proclock needlan
		DEVINITMARK="$(uci get xiaoqiang.common.INITTED 2>/dev/null)"
		if [ "$DEVINITMARK" = 'YES' ]
		then
			dlog "INFO: webinitrdr bypass for device already initialed."
			webinitrdr_disable
			return 0
		fi

		local is_webinit=$(uci -q get misc.firewall.webinit)
		is_webinit="${is_webinit:-1}"
		# boot_status no ready
		if [ $is_webinit == '0' ]; then
		    #NGINXWEBINITPORT=80
		    webinitrdr_disable
		    if [ "$DEVINITMARK" != 'YES' ]
		    then
			dlog "INFO: webinitrdr disabled for squash system."
			return $?
		    else
			dlog "INFO: device already initialed for squash system."
			return 0
		    fi
		fi
		#
		#rdr on
		#
		if [ "$INTERFACE" != "lan" -a -n "$INTERFACE" -a -n "$DEVICE" -a -n "$ACTION" ] ;then
			dlog "INFO: skip webinitrdr for interface ${INTERFACE}."
			return 0
		fi
		dlog "INFO: try to insert redirect rules and restart services."
		iptables -L prerouting_lan_rule -t nat 2>/dev/null | grep -qi 'HTTPWEBINITRDR'
		webrdrok=$?
		iptables -L prerouting_lan_rule -t nat 2>/dev/null| grep -qi 'DNSWEBINITRDR'
		dnsrdrok=$?
		if [ $webrdrok -ne 0 -o $dnsrdrok -ne 0 ]
			then
			test $webrdrok -ne 0 && iptexec "iptables -A $HTTPRDR_RULE"
			test $dnsrdrok -ne 0 && iptexec "iptables -A $DNSRDR_RULE"
			iptables -L prerouting_lan_rule -t nat 2>/dev/null| grep -qi 'HTTPWEBINITRDR'
			webrdrok=$?
			if [ $webrdrok -ne 0 ]
				then
				dlog "WARNING: preload catch all web init redirect on failed, miss HTTPWEBINITRDR rules."
			fi
			iptables -L prerouting_lan_rule -t nat 2>/dev/null| grep -qi 'DNSWEBINITRDR'
			dnsrdrok=$?
			if [ $dnsrdrok -ne 0 ]
				then
				dlog "WARNING: preload catch all dns init redirect on failed, miss DNSWEBINITRDR rules."
			fi
			if [ $webrdrok -eq 0 -a $dnsrdrok -eq 0 ]
				then
				dlog "INFO: web init redirect switch to on."
				test -x /usr/sbin/preload.monitor && dlog "INFO: restart preload.monitor for webinitrdr." && /usr/sbin/preload.monitor restart &
				test -x /etc/init.d/dnsmasq && dlog "INFO: restart dnsmasq for webinitrdr." && /etc/init.d/dnsmasq restart &
			else
				dlog "ERROR: web init redirect switch to on failed."
				errcount $?
			fi
		else
			dlog "INFO: redirect rules already exist, nothing to do."
		fi
		return $errcount
}

dnsmiwifi_doit(){
		#
		proclock needlan
		#
		#U32 match dns query www.miwifi.com/miwifi.com
		#
		#www.miwifi.com
		if [ "$INTERFACE" != "lan" -a -n "$INTERFACE" -a -n "$DEVICE" -a -n "$ACTION" ] ;then
			dlog "INFO: skip dnsmiwifi for interface ${INTERFACE}."
			return 0
		fi
		iptremoverule -D prerouting_lan_rule -t nat -p udp --dport 53 -m u32 --u32 "0>>22&0x3C@20&0xFFDFDFDF=0x03575757&&0>>22&0x3C@24&0xFFDFDFDF=0x064d4957&&0>>22&0x3C@28&0xDFDFDFFF=0x49464903&&0>>22&0x3C@32&0xDFDFDF00=0x434f4d00" -j REDIRECT --to-port 53
		iptables -A prerouting_lan_rule -t nat -p udp --dport 53 -m u32 --u32 "0>>22&0x3C@20&0xFFDFDFDF=0x03575757&&0>>22&0x3C@24&0xFFDFDFDF=0x064d4957&&0>>22&0x3C@28&0xDFDFDFFF=0x49464903&&0>>22&0x3C@32&0xDFDFDF00=0x434f4d00" -j REDIRECT --to-port 53
		errcount $?
		#miwifi.com
		iptremoverule -D prerouting_lan_rule -t nat -p udp --dport 53 -m u32 --u32 "0>>22&0x3C@20&0xFFDFDFDF=0x064d4957&&0>>22&0x3C@24&0xDFDFDFFF=0x49464903&&0>>22&0x3C@28&0xDFDFDF00=0x434f4d00" -j REDIRECT --to-port 53
		iptables -A prerouting_lan_rule -t nat -p udp --dport 53 -m u32 --u32 "0>>22&0x3C@20&0xFFDFDFDF=0x064d4957&&0>>22&0x3C@24&0xDFDFDFFF=0x49464903&&0>>22&0x3C@28&0xDFDFDF00=0x434f4d00" -j REDIRECT --to-port 53
		errcount $?
		#
		return 0
}

iptaccount_doit(){
	#
	proclock needlan
	#
	if [ "$INTERFACE" != "lan" -a -n "$INTERFACE" -a -n "$DEVICE" -a -n "$ACTION" ] ;then
		dlog "INFO: skip iptacount for interface ${INTERFACE}."
		return 0
	fi
	iptables -L POSTROUTING -t mangle --line-numbers 2>/dev/null | grep -q 'landownloadtraffic'
	test $? -eq 0 && iptremoverule "-D POSTROUTING -t mangle -o br-lan -j landownloadtraffic"
	iptables -L fwmark -t mangle --line-numbers 2>/dev/null | grep -q 'lanuploadtraffic'
	test $? -eq 0 && iptremoverule "-D fwmark -t mangle -i br-lan -j lanuploadtraffic"
	iptremoverule "-F landownloadtraffic -t mangle"
	iptremoverule "-F lanuploadtraffic -t mangle"
	iptremoverule "-X landownloadtraffic -t mangle"
	iptremoverule "-X lanuploadtraffic -t mangle"
	if [ "$addop" = 'stop' -o "$addop" = 'stop' ]
		then
		dlog "INFO: IP LAN TRAFFIC ACCOUNT rules removed."
		return 0
	fi
	dlog "INFO: setup IP LAN TRAFFIC ACCOUNT rules for $LANIPMASK ..."
	#-A POSTROUTING -o br-lan -m comment --comment "LANIPTRAFFICACCOUNT" -j landownloadtraffic
	iptnewchain "-N landownloadtraffic -t mangle"
	errcount $?
	iptables -L POSTROUTING -t mangle --line-numbers 2>/dev/null | grep '1 ' | grep -q 'landownloadtraffic'
	if [ $? -ne 0 ]
		then
		iptremoverule "-D POSTROUTING -t mangle -o br-lan -j landownloadtraffic"
		iptexec "iptables -I POSTROUTING -t mangle -o br-lan -j landownloadtraffic"
		errcount $?
	fi
	#-A fwmark -i br-lan -m comment --comment "LANIPTRAFFICACCOUNT" -j lanuploadtraffic
	iptnewchain "-N lanuploadtraffic -t mangle"
	errcount $?
	iptables -L fwmark -t mangle --line-numbers 2>/dev/null | grep '1 ' | grep -q 'lanuploadtraffic'
	if [ $? -ne 0 ]
		then
		iptremoverule "-D fwmark -t mangle -i br-lan -j lanuploadtraffic"
		iptexec "iptables -I fwmark -t mangle -i br-lan -j lanuploadtraffic"
		errcount $?
	fi
	#clean up rules in lanuploadtraffic, landownloadtraffic and re-create all
	iptremoverule "-F landownloadtraffic -t mangle"
	iptremoverule "-F lanuploadtraffic -t mangle"

	iptexec "iptables -A landownloadtraffic -t mangle -m comment --comment LANIPTRAFFICACCOUNT -j ACCOUNT --addr $LANIPMASK --tname landownloadtraffic"
	iptexec "iptables -A lanuploadtraffic -t mangle -m comment --comment LANIPTRAFFICACCOUNT -j ACCOUNT --addr $LANIPMASK --tname lanuploadtraffic"
	#
	chk=$(iptables -L landownloadtraffic -t mangle -n -v | grep -c 'LANIPTRAFFICACCOUNT')
	if [ $chk -lt 1 ]
		then
		dlog "ERROR: landownloadtraffic rules setup failed."
		errcount 1
	fi
	chk=$(iptables -L lanuploadtraffic -t mangle -n -v | grep -c 'LANIPTRAFFICACCOUNT')
	if [ $chk -lt 1 ]
		then
		dlog "ERROR: lanuploadtraffic rules setup failed."
		errcount 1
	fi

	return 0
}

macfilter_doit(){
	#
	proclock needlan
	#
	if [ "$INTERFACE" != "lan" -a -n "$INTERFACE" -a -n "$DEVICE" -a -n "$ACTION" ] ;then
		dlog "INFO: skip macfilter for interface ${INTERFACE}."
		return 0
	fi
	dlog "INFO: setup MACFILTER rules ..."
	lua /usr/sbin/macfilterctl init
	errcount $?

	errcount $?
}

ttl_doit(){
	 if [ "$(nvram get model 2>/dev/null)" != "R1CM" -a "$(nvram get model 2>/dev/null)" != "R1CQ" ]
		then
		dlog "INFO: platform $(nvram get model 2>/dev/null) skip setting TTL to 64"
		return 0
	fi
	local delnum=`iptables -t mangle --line-numbers -L POSTROUTING 2>/dev/null|awk '/TTL set to /{print$1}'`
	if [ -n "$delnum" ]
		then
		iptables -t mangle -D POSTROUTING $delnum 2>/dev/null
		if [ $? -eq 0 ]
			then
			dlog "INFO: unset TTL to 64 ok."
		else
			dlog "ERROR: unset TTL to 64 failed."
		fi
	fi

	local ttldevice=`getdefaultroutedev`
	if [ -n "$ttldevice" ]
		then
		iptables -t mangle -I POSTROUTING -o $ttldevice  -j TTL --ttl-set 64 2>/dev/null
		if [ $? -eq 0 ]
			then
			dlog "INFO: set $ttldevice TTL to 64 ok."
			return 0
		else
			dlog "ERROR: set $ttldevice TTL to 64 failed."
			return 1
		fi
	fi
	return 1
}

miqos_doit(){
    #initial miqos ipt mark
    /etc/init.d/miqos init_ipt

    #only active qos when boot-check is ready
    local stat=`cat /proc/xiaoqiang/boot_status 2>/dev/null`
    if [ "$stat" -eq "3" ]; then
        /etc/init.d/miqos restart
    fi

    return 0
}

xqfp_doit(){
    if [ -f /proc/xqfp/dbg_switch ]; then
        /etc/init.d/soft_fast_path fw_load
    fi

    return 0
}

smartproxy_doit(){
    [ -f "/usr/sbin/proxy_thirdparty.sh" ] && /usr/sbin/proxy_thirdparty.sh flush

    return 0
}

smartvpn_doit(){
    [ -f "/etc/init.d/smartvpn" ] && /etc/init.d/smartvpn start

    return 0
}

parentalctl_doit(){
    [ -f "/usr/sbin/parentalctl.sh" ] &&  /usr/sbin/parentalctl.sh reload

    return 0
}


kr_doit() {
    ipset flush    kr_query
    ipset destroy  kr_query
    ipset create   kr_query hash:net
    iptables -t mangle -A fwmark -p tcp -m set --match-set kr_query dst -m comment --comment kr_query -j MARK --set-xmark 0x4/0x4
}

APK_PROXY_INITD="/etc/init.d/http_apk_proxy"
apk_proxy_doit() {
    [ -f $APK_PROXY_INITD ] && $APK_PROXY_INITD reload_iptable_rule
    return 0
}

turbo_doit() {
    #ccgame
    ccgame=`uci -q get turbo.ccgame.name`
    ccgame_mark="0x0100/0x0300"
    tables="/etc/iproute2/rt_tables"

    [ -n "$ccgame" ] && {
        # create rt table name of $service
        grep -q $ccgame $tables || echo "150  $ccgame" >> $tables

        #create ipset if not exist
        ipset -q create $ccgame hash:ip

        iptables -t mangle -D fwmark -m set --match-set $ccgame dst -m comment --comment $ccgame -j MARK --set-xmark $ccgame_mark
        iptables -t mangle -A fwmark -m set --match-set $ccgame dst -m comment --comment $ccgame -j MARK --set-xmark $ccgame_mark
        lsmod | grep ctf && {
            iptables -t mangle -D fwmark -m set --match-set $ccgame dst -j SKIPCTF
            iptables -t mangle -A fwmark -m set --match-set $ccgame dst -j SKIPCTF
        }

        #collecting ip list for cc game
        [ -d /proc/net/xt_recent ] && {
            ipset -q create ${ccgame}_chk hash:net
            iptables -t nat -D PREROUTING -m set --match-set ${ccgame}_chk dst -m comment --comment ${ccgame}_chk -m recent --name $ccgame --set --rdest
            iptables -t nat -I PREROUTING -m set --match-set ${ccgame}_chk dst -m comment --comment ${ccgame}_chk -m recent --name $ccgame --set --rdest
        }

    }
}

modules_doit(){

	#prepare_doit

	### NAT rules ####
	if [ "$ctlop" = 'dnsmiwifi' ]
		then
		#suing chain prerouting_lan_rule
		dnsmiwifi_doit
		#test "$addop" = 'stop' -o "$addop" = 'off' && exit 0
	fi
	#
	if [ "$ctlop" = 'webinitrdr' ]
		then
		#using chain prerouting_lan_rule
		webinitrdr_doit
		##test "$addop" = 'stop' -o "$addop" = 'off' && exit 0
	fi
	#

	### INPUT rules ####

	### FORWARD rules ####

	### MANGLE rules ####
	# using chain fwmark, lanuploadtraffic(PREROUTING), landownloadtraffic(POSTROUTING), preroute-wan-mac, preroute-admin-mac, preroute-lan-mac
	#
	if [ "$ctlop" = 'iptaccount' ]
		then
		#
		iptaccount_doit
		#test "$addop" = 'stop' -o "$addop" = 'off' && exit 0
	fi
	#

	#
	if [ "$ctlop" = 'macfilter' ]
		then
		#
		macfilter_doit
		#test "$addop" = 'stop' -o "$addop" = 'off' && exit 0
	fi

	if [ "$ctlop" = 'ttlset' ]
		then
		# disable ttl_doit because it break ICMP
		exitcode=0
	fi
	#
	if [ "$ctlop" = 'miqos' ]
	then
		miqos_doit
	fi

	if [ "$ctlop" = 'xqfp' ]
	then
		xqfp_doit
	fi

	#
	if [ "$ctlop" = 'smartproxy' ]
	then
		smartproxy_doit
	fi
	#
	if [ "$ctlop" = 'smartvpn' ]
	then
		smartvpn_doit
	fi
	#
	if [ "$ctlop" = 'parentalctl' ]
	then
		parentalctl_doit
	fi
	#
	if [ "$ctlop" = 'kr_query' ]
	then
		kr_doit
	fi
	#
	if [ "$ctlop" = 'apk_proxy' ]
	then
		apk_proxy_doit
	fi
	#
	if [ "$ctlop" = 'dmz_bypass_ctf' ]
	then
		lua /usr/sbin/dmz_bypass_ctf
	fi
	#
	if [ "$ctlop" = 'turbo' ]
	then
		turbo_doit
	fi
    #
	return $exitcode
}

test -z "$addop" && addop='unset'
#
LANIPMASK="$(getlanipmask)"
export LANIPMASK
#
SCRIPTTAG="${SCRIPTTAG}_${ctlop}_${addop}"
SCRIPTLOCK="${SCRIPTMARK}_${ctlop}"
PROC_LOCK_DEBUG='TRUE'
#
dlog "INFO: executing $@"
#
modules_doit 2>&1 | pipelog dlog
if [ ${exitcode} -eq 0 ]
	then
	dlog "INFO: executing $@ exit with code ${exitcode}."
else
	dlog "ERROR: executing $@ exit with code ${exitcode}."
fi
exit $exitcode
#
