#!/bin/sh

. /lib/functions.sh

day=""
next_days=""
prev_days=""
schedule_added=""

ACCESS_RULE=""
IP_RULE=""
IP_RULE1=""

get_next_day() {
	local weekday="$1"
	case "$weekday" in
		"Mon"|"Monday") echo "Tuesday"
		;;
		"Tue"|"Tuesday") echo "Wednesday"
		;;
		"Wed"|"Wednesday") echo "Thursday"
		;;
		"Thu"|"Thursday") echo "Friday"
		;;
		"Fri"|"Friday") echo "Saturday"
		;;
		"Sat"|"Saturday") echo "Sunday"
		;;
		"Sun"|"Sunday") echo "Monday"
		;;
	esac
}

get_previous_day() {
	local weekday="$1"
	case "$weekday" in
		"Mon"|"Monday") echo "Sunday"
		;;
		"Tue"|"Tuesday") echo "Monday"
		;;
		"Wed"|"Wednesday") echo "Tuesday"
		;;
		"Thu"|"Thursday") echo "Wednesday"
		;;
		"Fri"|"Friday") echo "Thursday"
		;;
		"Sat"|"Saturday") echo "Friday"
		;;
		"Sun"|"Sunday") echo "Saturday"
		;;
	esac
}

ip_rule_west_zone() {
	local utc_start_t_h="$1"
	local utc_stop_t_h="$2"
	local local_start_t_h="$3"
	local local_stop_t_h="$4"
	local utc_start_time="$5"
	local utc_stop_time="$6"

	if [ "$utc_start_t_h" -lt "$local_start_t_h" ]; then
		IP_RULE="$IP_RULE -m time --timestart $utc_start_time --timestop $utc_stop_time"
		if [ -n "$next_days" ]; then
			IP_RULE="$IP_RULE --weekdays $next_days"
		fi
	else
		if [ "$utc_stop_t_h" -lt "$local_stop_t_h" ]; then
			IP_RULE1="$IP_RULE"
			IP_RULE="$IP_RULE -m time --timestart $utc_start_time --timestop 23:59"
			IP_RULE1="$IP_RULE1 -m time --timestart 00:00 --timestop $utc_stop_time"
			if [ -n "$next_days" ]; then
				IP_RULE1="$IP_RULE1 --weekdays $next_days"
			fi
		else
			IP_RULE="$IP_RULE -m time --timestart $utc_start_time --timestop $utc_stop_time"
		fi
		if [ -n "$day" ]; then
			IP_RULE="$IP_RULE --weekdays $day"
		fi
	fi
}

ip_rule_east_zone() {
	local utc_start_t_h="$1"
	local utc_stop_t_h="$2"
	local local_start_t_h="$3"
	local local_stop_t_h="$4"
	local utc_start_time="$5"
	local utc_stop_time="$6"

	if [ "$utc_start_t_h" -lt "$local_start_t_h" ]; then
		IP_RULE="$IP_RULE -m time --timestart $utc_start_time --timestop $utc_stop_time"
		if [ -n "$day" ]; then
			IP_RULE="$IP_RULE --weekdays $day"
		fi
	else
		if [ "$utc_stop_t_h" -lt "$local_stop_t_h" ]; then
			IP_RULE1="$IP_RULE"
			IP_RULE="$IP_RULE -m time --timestart 00:00 --timestop $utc_stop_time"
			IP_RULE1="$IP_RULE1 -m time --timestart $utc_start_time --timestop 23:59"
			if [ -n "$prev_days" ]; then
				IP_RULE1="$IP_RULE1 --weekdays $prev_days"
			fi
		else
			IP_RULE="$IP_RULE -m time --timestart $utc_start_time --timestop $utc_stop_time"
		fi
		if [ -n "$day" ]; then
			IP_RULE="$IP_RULE --weekdays $day"
		fi
	fi
}


add_access_rule() {
	local rule="$1"
	echo "iptables -w -A hosts_forward ${rule}" >> "$ACL_FILE"
	echo "ip6tables -w -A hosts_forward ${rule}" >> "$ACL_FILE"
}

handle_day_list() {
	local value=$1

	val=$(echo "$value" | cut -c 1-3)
	next_day_val=$(get_next_day "$val")
	prev_day_val=$(get_previous_day "$val")
	if [ -z $day ]; then
		day="$val"
		next_days="$next_day_val"
		prev_days="$prev_day_val"
	else
		day="$day,$val"
		next_days="$next_days,$next_day_val"
		prev_days="$prev_days,$prev_day_val"
	fi
}

handle_schedule() {
	local schd_section="$1"
	local start_time
	local duration

	IP_RULE="$ACCESS_RULE"
	IP_RULE1=""
	day=""
	next_days=""
	prev_days=""

	config_load schedules

	local is_enabled
	config_get is_enabled "$schd_section" "enable" 0
	if [ "$is_enabled" == "0" ]; then
		return
	fi

	local all_days="Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
	local day_config
	config_get day_config "$schd_section" "day" "$all_days"

	IFS=" "
	for d in $day_config; do
		handle_day_list "$d"
	done

	config_get start_time "$schd_section" "start_time" "00:00"
	config_get duration "$schd_section" "duration"

	zone=$(date +%z | cut -c 1)
	local_start_time=$start_time
	hh=$(echo "$local_start_time" | awk -F: '{ print $1 }')
	mm=$(echo "$local_start_time" | awk -F: '{ print $2 }')
	hh_s=`expr $hh \* 3600`
	mm_s=`expr $mm \* 60`
	ss=$(( hh_s + mm_s ))
	local_start_hh=$hh

        if [ -n "$duration" ]; then
                stop_ss=$(( ss + duration ))
                hh=$(( stop_ss / 3600 ))
               	rem_ss=$(( stop_ss % 3600 ))
               	mm=$(( rem_ss / 60 ))
               	ss=$(( rem_ss % 60 ))
		local_stop_time="$hh:$mm:$ss"
		local_stop_hh=$hh
	else
		# if duartion is not specified, then apply rule to end of the day
		local_stop_time="23:59:59"
		local_stop_hh="23"
	fi

	utc_start_time=$(date -u -d @$(date "+%s" -d "$local_start_time") +%H:%M)
	utc_stop_time=$(date -u -d @$(date "+%s" -d "$local_stop_time") +%H:%M)
	utc_start_hh=$(echo "$utc_start_time" | awk -F: '{ print $1 }')
	utc_stop_hh=$(echo "$utc_stop_time" | awk -F: '{ print $1 }')
	if [ "$zone" == "-" ]; then
		ip_rule_west_zone "$utc_start_hh" "$utc_stop_hh" "$local_start_hh" "$local_stop_hh" "$utc_start_time" "$utc_stop_time"
	else
		ip_rule_east_zone "$utc_start_hh" "$utc_stop_hh" "$local_start_hh" "$local_stop_hh" "$utc_start_time" "$utc_stop_time"
	fi

	IP_RULE="$IP_RULE -j ACCEPT"
	if [ -n "$IP_RULE1" ]; then
		IP_RULE1="$IP_RULE1 -j ACCEPT"
	fi

	add_access_rule "$IP_RULE"
	if [ -n "$IP_RULE1" ]; then
		add_access_rule "$IP_RULE1"
	fi

	# for access rules to be effective for a schedule, need to add DROP rule
	# to block the access outside the defined schedule
	if [ "$schedule_added" == "0" ]; then
		schedule_added="1"
	fi
}

handle_access_control() {
	local ac_section="$1"
	local is_enabled

	# default value of Hosts.AccessControl.{i}.Enable is false,
	# so, if not defined in uci as 1, assume 0
	config_get is_enabled "$ac_section" "enable" 0
	if [ "$is_enabled" == "0" ]; then
		return
	fi

	local mac_addr
	config_get mac_addr "$ac_section" "macaddr"
	if [ -z "$mac_addr" ]; then
		return
	else
		ACCESS_RULE="-m mac --mac-source $mac_addr"
	fi

	local access_policy
	config_get access_policy "$ac_section" "access_policy"
	if [ -z "$access_policy" ]; then
		return # since system default is allow so no need to do anything
	fi

	# As per Data Model, if access policy is deny, then schedule is to be ignored
	# and no access is to be provided for the device
	if [ "$access_policy" == "Deny" ]; then
		ACCESS_RULE="$ACCESS_RULE -j DROP"
		add_access_rule "$ACCESS_RULE"
		return # no need to parse schedule
	fi

	schedule_added="0"
	# check if schedule is defined for this access_control instance
	# and if yes, create rule accordingly
	config_list_foreach "$ac_section" access_control_schedule handle_schedule

	# for access rule to work, need to have default drop rule as last rule
	if [ "$schedule_added" == "1" ]; then
		IP_RULE="$ACCESS_RULE -j DROP"
		add_access_rule "$IP_RULE"
	fi
}

ACL_FILE="/tmp/hosts_access_control/access_control.rules"

rm -f $ACL_FILE

mkdir -p /tmp/hosts_access_control/
touch $ACL_FILE

echo "iptables -w -F hosts_forward" >> $ACL_FILE
echo "ip6tables -w -F hosts_forward" >> $ACL_FILE

hosts_ipv4_forward=$(iptables -w -t filter --list -n | grep hosts_forward)
if [ -z "$hosts_ipv4_forward" ]; then
	echo "iptables -w -t filter -N hosts_forward" >> $ACL_FILE
	ret=$?
	[ $ret -eq 0 ] && echo "iptables -w -t filter -I FORWARD -j hosts_forward" >> $ACL_FILE
fi

hosts_ipv6_forward=$(ip6tables -w -t filter --list -n | grep hosts_forward)
if [ -z "$hosts_ipv6_forward" ]; then
	echo "ip6tables -w -t filter -N hosts_forward" >> $ACL_FILE
	ret=$?
	[ $ret -eq 0 ] && echo "ip6tables -w -t filter -I FORWARD -j hosts_forward" >> $ACL_FILE
fi

# Load /etc/config/hosts UCI file
config_load hosts
config_foreach handle_access_control access_control

# apply the rules
sh $ACL_FILE
