#!/bin/sh

. /lib/functions.sh
. /usr/share/libubox/jshn.sh

ZONE_NAME_FILE="/tmp/mcast_fw_zone"

log() {
	echo "${@}"|logger -t firewall.mcast -p info
}

collect_zone_name() {
	local name network

	config_get name "${1}" name ""
	if [ -z "${name}" ]; then
		return
	fi

	config_get network "${1}" network ""
	for i in ${network}; do
		var="${i}_zone"
		echo "${var}=${name}" >> "${ZONE_NAME_FILE}"
	done
}

load_zone_names() {
	rm -f "${ZONE_NAME_FILE}"
	config_load firewall
	config_foreach collect_zone_name zone
}

get_firewall_zone() {
	if [ ! -f "${ZONE_NAME_FILE}" ]; then
		echo ""
		return
	fi

	var="${1}_zone="
	name="$(cat ${ZONE_NAME_FILE} | grep ${var} | head -n 1 | cut -d'=' -f 2)"

	echo "${name}"
}

# Get interface name for a device (e.g., br-lan -> lan)
find_interface_for_device() {
	local dev="${1}"
	local intf=""
	local intf_dump idx

	if [ -z "${dev}" ]; then
		echo ""
		return
	fi

	intf_dump="$(ubus -t 5 call network.interface dump)"
	if [ -z "${intf_dump}" ]; then
		echo ""
		return
	fi

	json_load "${intf_dump}"
	json_select interface
	if [ "$?" -ne 0 ]; then
		echo ""
		return
	fi

	idx=1
	while json_is_a ${idx} object; do
		json_select ${idx}
		if [ "$?" -ne 0 ]; then
			break
		fi

		json_get_var device device
		if [ "${device}" = "${dev}" ]; then
			json_get_var intf interface
			break
		fi

		idx=$(( idx + 1 ))
		json_select ..
	done

	echo "${intf}"
}

# Setup iptables rule to allow multicast from upstream to downstream
setup_multicast_rule() {
	local upstream_dev="$1"
	local downstream_dev="$2"
	local upstream_zone downstream_zone
	local upstream_iface downstream_iface

	upstream_iface=$(find_interface_for_device "$upstream_dev")
	downstream_iface=$(find_interface_for_device "$downstream_dev")

	[ -z "$upstream_iface" ] || [ -z "$downstream_iface" ] && {
		log "Failed to map devices to interfaces"
		return
	}

	upstream_zone=$(get_firewall_zone "$upstream_iface")
	downstream_zone=$(get_firewall_zone "$downstream_iface")

	[ -z "$upstream_zone" ] || [ -z "$downstream_zone" ] && {
		log "Failed to map interfaces to zones"
		return
	}

	iptables -w -t filter -A zone_${upstream_zone}_forward -p udp \
	  -d 224.0.0.0/240.0.0.0 \
	  -m comment --comment "!fw3: Allow-Multicast-UDP" \
	  -j zone_${downstream_zone}_dest_ACCEPT
}

apply_mcast_rule() {
	local cfg="$1"
	local up down proto

	config_get proto "$cfg" proto
	[ "$proto" = "igmp" ] || return

	config_get up "$cfg" upstream_interface
	config_get down "$cfg" downstream_interface

	[ -n "$up" ] && [ -n "$down" ] && setup_multicast_rule "$up" "$down"
}

add_multicast_rules() {
	config_load mcast
	config_foreach apply_mcast_rule proxy
}

load_zone_names

add_multicast_rules

rm -f "${ZONE_NAME_FILE}"
