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

######## Reserved Ports:
#	(<enable/disable> <port number definition>)
#1. (Default Fixed)DHCP Client udp packets on port: 68(IPv4),546(IPV6)
#		uci config:acc_ctrl; script:acc_ctrl
#2. (Default Custom)ipsec ISAKMP, ipsec NAT-t:
#		uci config:ipsec_config; script:ipsec.init
#3. (Toggle Fixed)L2TP: 1701
#		uci config:l2tpd_config; script:xl2tpd.init
#4. (Toggle Fixed)PPTP: 1723
#		uci config:pptpd_config; script:pptpd.init
#5. (Toggle Fixed)SNMP: 161
#		uci config:snmpd; script:snmpd.init
#6. (Toggle Custom)TR069: 
#		uci config:cwmp; script:cwmp.init
#7. (Toggle Custom)Allow remote access to local machine: custom(web_port,telnet_port,ssh_port,https_port)
#		uci config:acc_ctrl; script:acc_ctrl

START=88
ACC_CTRL="ACC_CTRL"
ACC6_CTRL="ACC6_CTRL"
PRE_NAT_FUNCS="PRE_NAT_FUNCS"
model=$(head -n 1 /etc/version)

append_multiport() {
	[ -z "$multiport" ] && multiport="$1" || multiport="$multiport,$1"
}
append_blockport() {
    [ -z "$multiblockport" ] && multiblockport="$1" || multiblockport="$multiblockport,$1"
}

acc_ctrl_config()
{
	local web_allow
	local web_port
	local telnet_allow
	local telnet_port
	local ssh_allow
	local ssh_port
	local https_allow
	local https_port
	local server_cert
	local user_define
	local allow_ip1
	local allow_ip2
	local allow_ip3
	local wan_ping_allow
	local lan_ping_allow
	local source_ip1
	local source_ip2
	local source_ip3
	local intf
	local block_lan
	multiport=""
	multiblockport=""
	config_get web_allow $1 web_allow
	config_get web_port $1 web_port
	config_get telnet_allow  $1 telnet_allow
	config_get telnet_port $1 telnet_port
	config_get ssh_allow $1 ssh_allow
	config_get ssh_port $1 ssh_port
	config_get https_allow $1 https_allow
	config_get https_port $1 https_port
	config_get server_cert $1 server_cert
	config_get user_define $1 user_define
	config_get allow_ip1 $1 allow_ip1
    config_get allow_ip2 $1 allow_ip2
    config_get allow_ip3 $1 allow_ip3
    config_get wan_ping_allow $1 wan_ping_allow
    config_get lan_ping_allow $1 lan_ping_allow
	config_get block_lan $1 block_lan
    #echo $https_port $block_lan $1> /dev/console
    allow_ip1_null=0
	allow_ip2_null=0
	allow_ip3_null=0
	if [ "$user_define" = "enable" ]; then
    	if [ "$allow_ip1" != "0.0.0.0/0" ] ;then
			source_ip1=" -s $allow_ip1"
		else
			allow_ip1_null=1
		fi
    	if [ "$allow_ip2" != "0.0.0.0/0" ] ;then
			source_ip2=" -s $allow_ip2"
		else
			allow_ip2_null=1
		fi
    	if [ "$allow_ip3" != "0.0.0.0/0" ] ;then
			source_ip3=" -s $allow_ip3"
		else
			allow_ip3_null=1
		fi
    fi   
    #restart lighttpd if port is changed
	local last_web_port=$(uci oget acc_ctrl.access_control.web_port)
    local last_https_port=$(uci oget acc_ctrl.access_control.https_port)  	    	
    local last_server_cert=$(uci oget acc_ctrl.access_control.server_cert)
    if [ "$last_web_port" != "$web_port" ] || [ "$last_https_port" != "$https_port" ] || [ "$last_server_cert" != "$server_cert" ];then
    	/etc/init.d/lighttpd restart 1>/dev/null 2>/dev/null
    fi
    
	#restart telnet if port is changed
    local last_telnet_port=$(uci oget acc_ctrl.access_control.telnet_port)    
    if [ "$telnet_port" != "$last_telnet_port" ];then
    	/etc/init.d/telnet restart 1>/dev/null 2>/dev/null
    fi
    
    #restart ssh if port is changed
	local last_ssh_port=$(uci oget acc_ctrl.access_control.ssh_port)
    if [ "$ssh_port" != "$last_ssh_port" ];then
    	/etc/init.d/dropbear restart 1>/dev/null 2>/dev/null
    fi
	
	#collect access ports
	if [ "$ssh_allow" == "enable" ] ;then
		append_multiport $ssh_port	
    else
        append_blockport $ssh_port	
	fi
	if [ "$web_allow" == "enable" ] ;then
		append_multiport $web_port	
    else
        append_blockport $web_port	
	fi
	if [ "$telnet_allow" == "enable" ] ;then
		append_multiport $telnet_port
    else
        append_blockport $telnet_port	
	fi   
	if [ "$https_allow" == "enable" ] ;then  
		append_multiport $https_port
    else
        append_blockport $https_port	
	fi
	
	# G41319:We need to accept udp packets on port 68,
	# see https://dev.openwrt.org/ticket/4108
	iptables -A $ACC_CTRL -i wan+ -p udp --dport 68 -j ACCEPT
	#DHCPv6 has the same issue: G41730
	ip6tables -A $ACC6_CTRL -i wan+ -p udp --dport 546 -j ACCEPT
	
	########Allow PING from WAN/LAN
    if [ "$wan_ping_allow" = "disable" ];then
		if [ "$lan_ping_allow" = "enable" ] ;then
			#allow ping from lan
			iptables -A $ACC_CTRL -i ppp+ -p icmp --icmp-type 8 -j ACCEPT
			iptables -A $ACC_CTRL -i lan+ -p icmp --icmp-type 8 -j ACCEPT
			ip6tables -A $ACC6_CTRL -i wan+ -p icmpv6 --icmpv6-type 128 -j DROP
			ip6tables -A $ACC6_CTRL -i lan+ -p icmpv6 --icmpv6-type 128 -j ACCEPT
		else
			#do not allow any ping
			iptables -A $ACC_CTRL -p icmp --icmp-type 8 -j DROP
			ip6tables -A $ACC6_CTRL -p icmpv6 --icmpv6-type 128 -j DROP
		fi
	else
		if [ "$lan_ping_allow" = "enable" ] ;then
			#allow ping from lan/wan
			iptables -A $ACC_CTRL -p icmp --icmp-type 8 -j ACCEPT
			ip6tables -A $ACC6_CTRL -p icmpv6 --icmpv6-type 128 -j ACCEPT
		else
			#allow ping from wan
			iptables -A $ACC_CTRL -i wan+ -p icmp --icmp-type 8 -m mset ! --set exception_subnet_set src ! --set exception_subnet_gre_set src -j ACCEPT
			iptables -A $ACC_CTRL -i wan+ -p icmp --icmp-type 8 -m mset --set exception_subnet_set src --set exception_subnet_gre_set src -j DROP
			iptables -A $ACC_CTRL -i ppp+ -p icmp --icmp-type 8 -j DROP
			iptables -A $ACC_CTRL -i lan+ -p icmp --icmp-type 8 -j DROP
			ip6tables -A $ACC6_CTRL -i wan+ -p icmpv6 --icmpv6-type 128 -j ACCEPT
			ip6tables -A $ACC6_CTRL -i lan+ -p icmpv6 --icmpv6-type 128 -j DROP
		fi
	fi
	
	######## Allow ICMPv6 from WAN/LAN
	ip6tables -A $ACC6_CTRL -p icmpv6 -j ACCEPT
	
	########User Defined IP: if it's enabled, only defined subnet can access local service ports
    if [ "$user_define" = "enable" -a -n "$multiport" ]; then
		if [ "$allow_ip1_null" = 0 -o "$allow_ip2_null" = 0 -o "$allow_ip3_null" = 0 ] ;then
			[ "$allow_ip1_null" = 0 ] && {
				iptables -A $ACC_CTRL -p tcp $source_ip1 -m multiport --dport $multiport -j ACCEPT
				iptables -t nat -I $PRE_NAT_FUNCS -p tcp $source_ip1 -m multiport --dport $multiport -j RETURN
			}
			[ "$allow_ip2_null" = 0 ] && {
				iptables -A $ACC_CTRL -p tcp $source_ip2 -m multiport --dport $multiport -j ACCEPT
				iptables -t nat -I $PRE_NAT_FUNCS -p tcp $source_ip2 -m multiport --dport $multiport -j RETURN
			}
			[ "$allow_ip3_null" = 0 ] && {
				iptables -A $ACC_CTRL -p tcp $source_ip3 -m multiport --dport $multiport -j ACCEPT
				iptables -t nat -I $PRE_NAT_FUNCS -p tcp $source_ip3 -m multiport --dport $multiport -j RETURN
			}
		else
			logger "(WebUI access control), ERROR: It must have at least one non-zero IP in \"Allowed IP\""
			uci set acc_ctrl.$1.user_define=disable	
            if [ -n "$block_lan" ]; then		       
		        for ifs in $block_lan; do 
	               iptables -A $ACC_CTRL -i lan-$ifs -p tcp -m multiport --dport $multiblockport -j DROP
			       ip6tables -A $ACC6_CTRL -i lan-$ifs -p tcp -m multiport --dport $multiblockport -j DROP
		        done
		    fi		
		fi
	    	
	elif [ -n "$multiport" ]; then
	    if [ -n "$block_lan" ]; then		
		    for ifs in $block_lan; do 
	          iptables -A $ACC_CTRL -i lan-$ifs -p tcp -m multiport --dport $multiblockport -j DROP
			  ip6tables -A $ACC6_CTRL -i lan-$ifs -p tcp -m multiport --dport $multiblockport -j DROP
		    done
		fi
		iptables -A $ACC_CTRL -p tcp -m multiport --dport $multiport -j ACCEPT
		iptables -t nat -I $PRE_NAT_FUNCS -p tcp -m multiport --dport $multiport -j RETURN
		ip6tables -A $ACC6_CTRL -p tcp -m multiport --dport $multiport -j ACCEPT
	elif [ -n "$multiblockport" ]; then
        if [ -n "$block_lan" ]; then		
		    for ifs in $block_lan; do 
	          iptables -A $ACC_CTRL -i lan-$ifs -p tcp -m multiport --dport $multiblockport -j DROP
			  ip6tables -A $ACC6_CTRL -i lan-$ifs -p tcp -m multiport --dport $multiblockport -j DROP
		    done
		fi
	
	fi
	
	if [ "$model" = "Vigor3900" -o "$model" = "Vigor2960" -o "$model" = "Vigor2960F" ]; then
		########Open global regular service port/protocol:
		ikeport=`uci get ipsec_config.ipsec.ikeport`
		natport=`uci get ipsec_config.ipsec.natport`
		iptables -A ACC_CTRL -i wan+ -p udp -m multiport --dport $ikeport,$natport -j ACCEPT
		iptables -A $ACC_CTRL -i wan+ -p esp -j ACCEPT	#allow ipsec
		iptables -A $ACC_CTRL -i wan+ -p ah -j ACCEPT	#allow ipsec proto to router
		iptables -A $ACC_CTRL -i wan+ -p 47 -j ACCEPT	#allow gre proto to local
	fi
}
start() {
	config_load acc_ctrl
	config_foreach acc_ctrl_config acc_ctrl
}

stop() {
	apply
}

apply() 
{
	iptables -F $ACC_CTRL 2>/dev/null
	ip6tables -F $ACC6_CTRL 2>/dev/null
	
	########Handle ip6tables
	local web_allow
	local web_port
	local telnet_allow
	local telnet_port
	local ssh_allow
	local ssh_port
	local https_allow
	local https_port
	multiport=""
	web_allow=$(uci oget acc_ctrl.access_control.web_allow)
	web_port=$(uci oget acc_ctrl.access_control.web_port)
	telnet_allow=$(uci oget acc_ctrl.access_control.telnet_allow)
	telnet_port=$(uci oget acc_ctrl.access_control.telnet_port)
	ssh_allow=$(uci oget acc_ctrl.access_control.ssh_allow)
	ssh_port=$(uci oget acc_ctrl.access_control.ssh_port)
	https_allow=$(uci oget acc_ctrl.access_control.https_allow)
	https_port=$(uci oget acc_ctrl.access_control.https_port)
	user_define=$(uci oget acc_ctrl.access_control.user_define)
	allow_ip1=$(uci oget acc_ctrl.access_control.allow_ip1)
	allow_ip2=$(uci oget acc_ctrl.access_control.allow_ip2)
	allow_ip3=$(uci oget acc_ctrl.access_control.allow_ip3)
	
	if [ "$user_define" = "enable" ]; then
		if [ "$allow_ip1" != "0.0.0.0/0" ];then
			source_ip1=" -s $allow_ip1"
		fi
		if [ "$allow_ip2" != "0.0.0.0/0" ];then
			source_ip2=" -s $allow_ip2"
		fi
		if [ "$allow_ip3" != "0.0.0.0/0" ];then
			source_ip3=" -s $allow_ip3"
		fi
	fi
	
	#collect access ports
	if [ "$ssh_allow" == "enable" ] ;then
		append_multiport $ssh_port
	fi
	if [ "$web_allow" == "enable" ] ;then
		append_multiport $web_port
	fi
	if [ "$telnet_allow" == "enable" ] ;then
		append_multiport $telnet_port
	fi   
	if [ "$https_allow" == "enable" ] ;then  
		append_multiport $https_port
	fi
	
    if [ "$user_define" == "enable" -a -n "$multiport" ]; then
		iptables -t nat -D $PRE_NAT_FUNCS -p tcp $source_ip1 -m multiport --dport $multiport -j RETURN 2>/dev/null
		iptables -t nat -D $PRE_NAT_FUNCS -p tcp $source_ip2 -m multiport --dport $multiport -j RETURN 2>/dev/null
		iptables -t nat -D $PRE_NAT_FUNCS -p tcp $source_ip3 -m multiport --dport $multiport -j RETURN 2>/dev/null
	elif [ -n "$multiport" ]; then
		iptables -t nat -D $PRE_NAT_FUNCS -p tcp -m multiport --dport $multiport -j RETURN 2>/dev/null
	fi
	
	start
	uci commit acc_ctrl
}

boot()
{
	#First policy:
	iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
	ip6tables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
	#Final policy: Accept rest packets which are coming through lan+, ppp+(remote dial-in, pppoe server), lan-to-lan vpn
	iptables -A INPUT -i wan+ -m mset ! --set exception_subnet_set src ! --set exception_subnet_gre_set src -j DROP
	ip6tables -A INPUT -i wan+ -j DROP
	#ipv6 default FORWARD policy
	ip6tables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
	ip6tables -A FORWARD -i wan+ -j DROP

	if [ "$model" = "Vigor3900" -o "$model" = "Vigor2960" -o "$model" = "Vigor2960F" ]; then
		##Prevent forwarded by NAT functions
		iptables -t nat -I $PRE_NAT_FUNCS -i wan+ -p esp -j RETURN
		iptables -t nat -I $PRE_NAT_FUNCS -i wan+ -p ah -j RETURN
		iptables -t nat -I $PRE_NAT_FUNCS -i wan+ -p 47 -j RETURN
	fi
	iptables -t nat -I $PRE_NAT_FUNCS -p udp -m multiport --dport 68,546 -j RETURN
	#G36963: skip these ports from ddos check
	ddos_status=$(uci get ddos.ddos_config.status)
	if [ "$ddos_status" = "enable" ] ;then
		echo $web_port > /proc/sys/net/ipv4/ddos_bypass_web_port
		echo $telnet_port > /proc/sys/net/ipv4/ddos_bypass_telnet_port
		echo $ssh_port > /proc/sys/net/ipv4/ddos_bypass_ssh_port
		echo $https_port > /proc/sys/net/ipv4/ddos_bypass_https_port
    fi
	start
}
