#!/bin/bash

COMMAND=$1

CHAIN=perfSONAR

#Determine BWCTL and OWAMP ports
BWCTLPARAMS=("iperf_port" "nuttcp_port" "owamp_port" "peer_port")
BWCTLDEFAULTS=("5001:5300" "5301:5600" "5601:5900" "6001:6200")
OWAMPPARAMS=("testports")
OWAMPDEFAULTS=("8760:9960")

BWCTLFILE="/etc/bwctld/bwctld.conf"
OWAMPFILE="/etc/owampd/owampd.conf"
FIREWALL_RULES="/opt/perfsonar_ps/toolkit/etc/perfsonar_firewall_settings.conf"
DEFAULT_FIREWALL_RULES="/opt/perfsonar_ps/toolkit/etc/default_system_firewall_settings.conf"
OLD_FIREWALL_RULES="/opt/perfsonar_ps/toolkit/etc/old_firewall_settings.conf"

if [ ! -f $FIREWALL_RULES ]; then
    echo "Couldn't find firewall rules"
    exit -1
fi

main() {
    if [ "${COMMAND}" == "new" ]; then
	# We're running as part of a NetInstall. Configure the firewall by hand
	# since iptables isn't available during NetInstall.
        buildStaticFirewallRules v4_rules "v4"
        buildStaticFirewallRules v6_rules "v6"

        mv $v4_rules /etc/sysconfig/iptables
        mv $v6_rules /etc/sysconfig/ip6tables
    elif [ "${COMMAND}" == "upgrade" ]; then
        deleteOldFirewallRules

        echo "Adding perfSONAR firewall rules"
        addFirewallRules

        saveFirewallRules
    fi
}

# The buildStaticFirewallRules constructs an iptables-restore compatible
# version of the default firewall rules. It returns the filename of the
# generated file.
buildStaticFirewallRules() {
    output_file=$1
    build_v6=$2

    tempfile=`mktemp`

    perfsonar_rules=""
    if [ -f $FIREWALL_RULES ]; then
        while read rule  
        do  
          case ${rule} in
              *"icmp "*)
              if [ "$build_v6" == "v4" ]; then
                  perfsonar_rules="${perfsonar_rules}\n${rule}"
              fi
              ;;
              *"icmpv6"*)
              if [ "$build_v6" == "v6" ]; then
                  perfsonar_rules="${perfsonar_rules}\n${rule}"
              fi
              ;;
              *)
              perfsonar_rules="${perfsonar_rules}\n${rule}"
              ;;
          esac
        done <$FIREWALL_RULES
    fi

perfsonar_rules=":perfSONAR - [0:0]\n${perfsonar_rules}\n-A ${CHAIN} -j RETURN\n-A INPUT -j ${CHAIN}\n"

static_rules=""
readarray firewall_rules < ${DEFAULT_FIREWALL_RULES}
for rule in "${firewall_rules[@]}"; do
    case ${rule} in
        *"[% default_perfsonar_rules %]"*)
        echo -e $perfsonar_rules >> $tempfile
        ;;
        *)
        echo $rule >> $tempfile
        ;;
    esac
done

eval $output_file=\$tempfile
}

saveFirewallRules() {
    for iptables_cmd in "iptables" "ip6tables"; do
        service $iptables_cmd save
    done
}

deleteOldFirewallRules(){
    for iptables_cmd in "iptables" "ip6tables"; do
        readarray firewall_rules < ${OLD_FIREWALL_RULES}
        for rule in "${firewall_rules[@]}"; do
            case ${rule} in
                "-D INPUT"*)
                    $iptables_cmd $rule &> /dev/null
                    ;;
            esac
        done

        p=`echo ${BWCTLPARAMS[@]}`;
        deletePortRuleFromFile "$iptables_cmd" "$BWCTLFILE" "$p";
        p=`echo ${OWAMPPARAMS[@]}`;
        deletePortRuleFromFile "$iptables_cmd" "$OWAMPFILE" "$p";
    done
}

addFirewallRules(){
    for iptables_cmd in "iptables" "ip6tables"; do
        # Create the chain if it doesn't currently exit
        $iptables_cmd -n -L $CHAIN &> /dev/null
        if [ $? != 0 ]; then
            $iptables_cmd -N $CHAIN
            if [ $? != 0 ]; then
                echo "Problem createing firewall chain";
                exit -1;
            fi
        fi

        $iptables_cmd -F $CHAIN
        if [ $? != 0 ]; then
            echo "Problem removing existing firewall rules";
            exit -1;
        fi

        readarray firewall_rules < ${FIREWALL_RULES}
        for rule in "${firewall_rules[@]}"; do
            case ${rule} in
                "-A ${CHAIN}"*)
                    $iptables_cmd $rule &> /dev/null
                    ;;
                "-I ${CHAIN}"*)
                    $iptables_cmd $rule &> /dev/null
                    ;;
            esac
        done

        p=`echo ${BWCTLPARAMS[@]}`;
        d=`echo ${BWCTLDEFAULTS[@]}`
        addPortRuleFromFile "$iptables_cmd" "$BWCTLFILE" "$p" "$d";
        p=`echo ${OWAMPPARAMS[@]}`;
        d=`echo ${OWAMPDEFAULTS[@]}`
        addPortRuleFromFile "$iptables_cmd" "$OWAMPFILE" "$p" "$d";

        # Add a rule at the end to jump us back to the main process chain
        $iptables_cmd -A ${CHAIN} -j RETURN

        # Make sure that there's an INPUT rule to point us into the 
        $iptables_cmd -n -L INPUT | grep -q "${CHAIN}[ \t]"
        if [ $? != 0 ]; then
            $iptables_cmd -I INPUT -j ${CHAIN}
        fi
    done
}

addPortRuleFromFile(){
	iptables_cmd=$1
	file=$2
	local params=( `echo "$3"` )
	local defaults=( `echo "$4"` )

	total=${#params[*]}
	for (( i=0; i<=$(( $total - 1 )); i++ ))
	do
		param_name="${params[$i]}"
		param_default="${defaults[$i]}"
		portrange=`awk -v search="^$param_name" '$0 !~ /^#/ && $0 ~ search {$1=""; print $0}' $file | sed s/-/:/g`

		if [ -z "$portrange" ]; then
			portrange=$param_default
			echo "Unable to find definition for \"$param_name\" in \"$file\" for \"$iptables_cmd\", using default of \"$portrange\""
		fi

		if [ ! -z "$portrange" ]; then
			$iptables_cmd -A $CHAIN -m udp -p udp --dport $portrange -j ACCEPT
			$iptables_cmd -A $CHAIN -m state --state NEW,ESTABLISHED -m tcp -p tcp --dport $portrange -j ACCEPT
			$iptables_cmd -A $CHAIN -m udp -p udp --dport $portrange -j ACCEPT
			$iptables_cmd -A $CHAIN -m state --state NEW,ESTABLISHED -m tcp -p tcp --dport $portrange -j ACCEPT
		fi
	done 
}

deletePortRuleFromFile(){
	iptables_cmd=$1
	file=$2
	local params=( `echo "$3"` )
	for i in "${params[@]}"
	do
		portrange=`awk -v search="^$i" '$0 !~ /^#/ && $0 ~ search {$1=""; print $0}' $file | sed s/-/:/g`
		if [ ! -z "$portrange" ]; then
			$iptables_cmd -D INPUT -m udp -p udp --dport $portrange -j ACCEPT &> /dev/null
			$iptables_cmd -D INPUT -m state --state NEW,ESTABLISHED -m tcp -p tcp --dport $portrange -j ACCEPT &> /dev/null
			$iptables_cmd -D INPUT -m udp -p udp --dport $portrange -j ACCEPT &> /dev/null
			$iptables_cmd -D INPUT -m state --state NEW,ESTABLISHED -m tcp -p tcp --dport $portrange -j ACCEPT &> /dev/null
		fi
	done 
}

main

exit 0
