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

####### Error code table
#101: No Alias
#102: Target outgoing WAN is not available

START=50

IPTABLES=iptables
UCI_CONFIG=dmz
CGI_ERROR_MSG="/tmp/cgi_error_msg"
HASHTABLE="$UCI_CONFIG"
UCI_TMP_PATH="/tmp/.uci/$UCI_CONFIG"

wan4_status=`uci get network.wan4.status`
wan4_proto=`uci get network.wan4.proto`
wan4_dmz_mode=`uci get network.wan4.dmz_mode`

source /etc/func_htable.sh

handle_rules(){
	ipset -A nat_dmz $private_ip
	#Determine DMZ case: NORMAL LAN DMZ, WAN4 DMZ NAT, WAN4 DMZ ROUTING
	dmz_case=""
	if [ "$wan4_status" = "disable" -o "$wan4_proto" != "dmz" ] ;then
		#If WAN4 is not "enabled+dmz" => normal LAN dmz:
		dmz_case="nat_dmz"
		ht_put $HASHTABLE $1 CASE "nat_dmz"
	elif [ "$wan4_dmz_mode" = "nat" ] ;then
		#When WAN4 is "enabled+dmz+NAT", cases of normal LAN dmz or WAN4 NAT DMZ can be treat the same, but not WAN4 ROUTING DMZ
		ipset -T lan_nat_subnet $private_ip >/dev/null 2>/dev/null
		if [ "$?" = "0" ] ;then
			dmz_case="nat_dmz"
			ht_put $HASHTABLE $1 CASE "nat_dmz"
		else
			dmz_case="routing_dmz"
			ht_put $HASHTABLE $1 CASE "routing_dmz"
		fi
	elif [ "$wan4_dmz_mode" = "routing" ] ;then
		#When WAN4 is "enabled+dmz+ROUTING", if DMZ Host IP is belong to LAN NAT subnets=>Normal LAN DMZ
		ipset -T lan_nat_subnet $private_ip >/dev/null 2>/dev/null
		if [ "$?" = "0" ] ;then
			dmz_case="nat_dmz"
			ht_put $HASHTABLE $1 CASE "nat_dmz"
		else
			dmz_case="routing_dmz"
			ht_put $HASHTABLE $1 CASE "routing_dmz"
		fi
	fi
	
	## For normal LAN DMZ Host and WAN4 DMZ(NAT mode)
	if [ "$dmz_case" = "nat_dmz" ] ;then
		$IPTABLES -t nat -A nat_dmz $dip -j DNAT --to-destination $private_ip
		#jtarget="MASQUERADE"
		#G46996: use special SNAT to replace MASQUERADE
		jtarget="SNAT --to-source 0.0.0.0"
		$IPTABLES -t nat -A nat_dmz_loopback -m set --set lan_nat_subnet src -d $private_ip -j $jtarget
		ht_put $HASHTABLE $1 DNAT "$dip -j DNAT --to-destination $private_ip"
		ht_put $HASHTABLE $1 NATLB "-m set --set lan_nat_subnet src -d $private_ip -j $jtarget"
	fi
	## Allow reply traffic from WAN4 to LAN Host
	$IPTABLES -t mangle -I DMZ_ACCESS_ZONE -s $private_ip -m state --state ESTABLISHED,RELATED -j ACCEPT
	ht_put $HASHTABLE $1 ROUTE "-s $private_ip -m state --state ESTABLISHED,RELATED -j ACCEPT"
	
	## Allow DMZ Host to access limited network
	ip_set=""
	service_set=""
	if [ "$allow_access" = "enable" ] ;then
		for item in $dst_ip_obj; do
			ipset -L ipo_$item >/dev/null 2>/dev/null
			[ "$?" = "0" ] && {
				ip_set=$ip_set"--set2 ipo_$item dst "
			}
		done
		for item in $dst_ip_grp; do
			ipset -L ipo_$item >/dev/null 2>/dev/null
			[ "$?" = "0" ] && {
				ip_set=$ip_set"--set2 ipo_$item dst "
			}
		done
		for item in $servicetype; do
			ipset -L svo_$item >/dev/null 2>/dev/null
			[ "$?" = "0" ] && service_set="$service_set --set2 svo_$item src"
		done
		$IPTABLES -t mangle -I DMZ_ACCESS_ZONE -s $private_ip ${ip_set:+-m mset2 $ip_set} ${service_set:+-m mset2 $service_set} -j ACCEPT
		ht_put $HASHTABLE $1 ACC "-s $private_ip ${ip_set:+-m mset2 $ip_set} ${service_set:+-m mset2 $service_set} -j ACCEPT"
	fi
	## Final, drop all from DMZ Host if it's not accepted by allow_access
	$IPTABLES -t mangle -A DMZ_DROP_ZONE -s $private_ip -j DROP
	ht_put $HASHTABLE $1 DROP "-s $private_ip -j DROP"
}


fw_dmz_boot(){
	#Handle Version Upgrade
	config_get allow_access $1 allow_access
	[ -z "$allow_access" ] && {
		uci set dmz.$1.allow_access=enable
		allow_access="enable"
	}
	config_get status $1 status
	[ "$status" != "enable" ] && return
	config_get intf $1 intf
	config_get use_ipalias $1 use_ipalias
	config_get ip_alias $1 ip_alias
	config_get private_ip $1 private_ip
	config_get dst_ip_obj $1 dst_ip_obj
	config_get dst_ip_grp $1 dst_ip_grp
	config_get servicetype $1 servicetype
	
	[ "$use_ipalias" = "enable" -a -z "$ip_alias" ] && {
		uci set $UCI_CONFIG.$1.status="disable"
		return
	}
	if [ "$use_ipalias" = "disable" ] ; then
		ipset -L ip_$intf >/dev/null 2>/dev/null
		if [ "$?" = "0" ] ;then
			dip="-m set --set ip_$intf dst"
			uci set $UCI_CONFIG.$1.ip_alias=
		else
			return
		fi
	else
		ip_alias=$(echo $ip_alias | cut -d '/' -f 1)
		dip="-d $ip_alias"
	fi
	handle_rules $1
}

fw_dmz_delete(){
	dmz_case=`ht_get $HASHTABLE $1 CASE`
	if [ "$dmz_case" = "nat_dmz" ] ;then
		DNAT_RULE=`ht_get $HASHTABLE $1 DNAT`
		NATLB_RULE=`ht_get $HASHTABLE $1 NATLB`
		ROUTE_RULE=`ht_get $HASHTABLE $1 ROUTE`
		ACC_RULE=`ht_get $HASHTABLE $1 ACC`
		$IPTABLES -t nat -D nat_dmz $DNAT_RULE
		$IPTABLES -t nat -D nat_dmz_loopback $NATLB_RULE
		$IPTABLES -t mangle -D DMZ_ACCESS_ZONE $ROUTE_RULE
		[ -n "$ACC_RULE" ] && $IPTABLES -t mangle -D DMZ_ACCESS_ZONE $ACC_RULE
	elif [ "$dmz_case" = "routing_dmz" ] ;then
		ROUTE_RULE=`ht_get $HASHTABLE $1 ROUTE`
		ACC_RULE=`ht_get $HASHTABLE $1 ACC`
		$IPTABLES -t mangle -D DMZ_ACCESS_ZONE $ROUTE_RULE
		[ -n "$ACC_RULE" ] && $IPTABLES -t mangle -D DMZ_ACCESS_ZONE $ACC_RULE
	fi
	DROP_RULE=`ht_get $HASHTABLE $1 DROP`
	$IPTABLES -t mangle -D DMZ_DROP_ZONE $DROP_RULE
	
	ht_rm_file $HASHTABLE $1
	
	private_ip=$(uci oget dmz.$1.private_ip)
	ipset -D nat_dmz $private_ip
}
fw_dmz_apply() {
	status=$(uci get dmz.$1.status)
	[ "$status" != "enable" ] && return
	intf=$(uci get dmz.$1.intf)
	use_ipalias=$(uci get dmz.$1.use_ipalias)
	ip_alias=$(uci get dmz.$1.ip_alias)
	private_ip=$(uci get dmz.$1.private_ip)
	allow_access=$(uci get dmz.$1.allow_access)
	dst_ip_obj=$(uci get dmz.$1.dst_ip_obj)
	dst_ip_grp=$(uci get dmz.$1.dst_ip_grp)
	servicetype=$(uci get dmz.$1.servicetype)
	
	[ "$use_ipalias" = "enable" -a  -z "$ip_alias" ] && {
		uci set $UCI_CONFIG.$1.status="disable"
		echo -n "DMZ Host(ERROR): No such alias<br>" >>$CGI_ERROR_MSG
		exit 101
	}
	if [ "$use_ipalias" = "disable" ] ; then
		ipset -L ip_$intf >/dev/null 2>/dev/null
		if [ "$?" = "0" ] ;then
			dip="-m set --set ip_$intf dst"
			uci set $UCI_CONFIG.$1.ip_alias=
		else
			uci set $UCI_CONFIG.$1.status="disable"
			echo -n "DMZ Host(ERROR): The status of target outgoing interface is disabled<br>" >>$CGI_ERROR_MSG
			exit 102
		fi
	else
		ip_alias=$(echo $ip_alias | cut -d '/' -f 1)
		dip="-d $ip_alias"
	fi
	handle_rules $1
}

start() {
	ht_init $HASHTABLE
	config_foreach fw_dmz_boot dmz_profile
}
stop() {
	$IPTABLES -t nat -F nat_dmz
	$IPTABLES -t nat -F nat_dmz_loopback
	$IPTABLES -t mangle -F DMZ_ACCESS_ZONE
	$IPTABLES -t mangle -F DMZ_DROP_ZONE
	$IPTABLES -t mangle -A DMZ_ACCESS_ZONE -j DMZ_DROP_ZONE
	ipset -F nat_dmz
	config_load $UCI_CONFIG
}

boot() {
	#This ipset is used in user management firewall mode to skip login access
	#ipset -N nat_dmz iphash  #has been moved to /etc/init.d/init_default_ipset
	config_load $UCI_CONFIG
	start
}

rename_rule() {
	ht_rename_file $HASHTABLE $1 $2
}

apply() {
	chage=$(uci fchanges delete dmz)
	for profile in ${chage}; do
		fw_dmz_delete $profile
	done
	
	chage=$(uci fchanges new dmz)
	for profile in ${chage}; do
		fw_dmz_apply $profile
	done
	
	chage=$(uci fchanges modify dmz)
	for profile in ${chage}; do
		action_type=`cat $UCI_TMP_PATH`
		if [ $(echo $action_type |grep '@') ] ;then
			#a profile renaming action
			old=`echo $action_type|sed 's/.*\.//'|awk '{FS="="; print $1}'`
			rename_rule $old $profile
		else
			fw_dmz_delete $profile
			fw_dmz_apply $profile
		fi
	done
	
	uci commit $UCI_CONFIG
}