#!/bin/bash

if [[ "$1" == "-verify" ]]; then
    verify=true
    shift
else
    verify=false
fi

tun=$1
shift
block_local_dns=$1 #not supported
shift

IPT="iptables -w -t filter"
if grep -q ':' "$1" ; then
    IPT6="ip6tables -w -t filter"
else
    IPT6="true"
fi

ipt4()
{
    if [[ "$verify" == true ]]; then
	op=$1
	shift
	if [[ "$op" == "-A" ]]; then
	    $IPT -C $* || exit 1
	fi
    else
	$IPT $*
    fi
}

ipt6()
{
    if [[ "$verify" == true ]]; then
	op=$1
	shift
	if [[ "$op" == "-A" ]]; then
	    $IPT6 -C $* || exit 1
	fi
    else
	$IPT6 $*
    fi
}

ipt()
{
    ipt4 $*
    ipt6 $*
}

[[ "$verify" == true ]] || touch /var/run/.appgate-fw-enabled

ipt -N appgate-filter-input
direct=$(iptables -n -w -t filter -L INPUT 2>/dev/null | grep -q INPUT_direct && echo _direct)
ipt -D INPUT$direct -j appgate-filter-input 2>/dev/null || true
ipt -A INPUT$direct -j appgate-filter-input
ipt -N appgate-filter-output
direct=$(iptables -n -w -t filter -L OUTPUT 2>/dev/null | grep -q OUTPUT_direct && echo _direct)
ipt -D INPUT$direct -j appgate-filter-output 2>/dev/null || true
ipt -A OUTPUT$direct -j appgate-filter-output

# accept everything on loopback
ipt -A appgate-filter-input -i lo -j ACCEPT
ipt -A appgate-filter-output -o lo -j ACCEPT

# accept everything on our tun-device
ipt -A appgate-filter-input -i $tun -j ACCEPT
ipt -A appgate-filter-output -o $tun -j ACCEPT

# pass required ICMPv6 NDP packets
ipt6 -A appgate-filter-input -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT
ipt6 -A appgate-filter-input -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT
ipt6 -A appgate-filter-input -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT
ipt6 -A appgate-filter-input -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT
ipt6 -A appgate-filter-output -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT
ipt6 -A appgate-filter-output -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT
ipt6 -A appgate-filter-output -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT
ipt6 -A appgate-filter-output -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT

# pass DHCPv4/v6
ipt4 -A appgate-filter-input -p udp --sport 67 --dport 68 -j ACCEPT
ipt4 -A appgate-filter-output -p udp --sport 68 --dport 67 -j ACCEPT
ipt6 -A appgate-filter-input -p udp -s fe80::/10 --sport 547 -d fe80::/10 --dport 546 -j ACCEPT
ipt6 -A appgate-filter-output -p udp -s fe80::/10 --sport 546 -d ff00::/8 --dport 547 -j ACCEPT

rules_added=false

while IFS='' read -r line || [[ -n "$line" ]]; do
    if [[ $rules_added = "false" ]]; then
	# If we have any rules we should start our set with acceping already accepted, or dropping invalid
	ipt -A appgate-filter-input -m state --state ESTABLISHED,RELATED -j ACCEPT
	ipt -A appgate-filter-output -m state --state RELATED,ESTABLISHED -j ACCEPT
	ipt -A appgate-filter-output -m state --state INVALID -j DROP
	ipt -A appgate-filter-input -m state --state INVALID -j DROP
	rules_added=true
    fi

    IFS=';' read -ra a <<< "$line"

    if [[ ${a[0]} = "allow" ]]; then
	action="ACCEPT"
    else
	action="DROP"
    fi

    if [[ ${a[1]} = "in" ]]; then
	filter="appgate-filter-input"
	ip_dir="-s"
    else
	filter="appgate-filter-output"
	ip_dir="-d"
    fi

    ip=${a[3]}
    proto=${a[4]}
    if [[ $proto != "" ]]; then
	proto="-p $proto"
    fi

    if [[ ${a[5]} != "" ]]; then
	if [[ ${a[4]} = "icmp"* ]]; then
	    if [[ ${a[5]} = ${a[6]} ]]; then
		port="--${a[4]}-type ${a[5]}"
	    else
		port=""
	    fi
	else
	    port="--dport ${a[5]}:${a[6]}"
	fi
    else
	port=""
    fi

    if [[ $ip != *":"* ]]; then
        ipt4 -A $filter -j $action $ip_dir $ip $proto $port
    else
        ipt6 -A $filter -j $action $ip_dir $ip $proto $port
    fi
done < "$1"

rm -f "$1"

if [[ "$rules_added" == true ]]; then
    ipt -A appgate-filter-input -j DROP
    ipt -A appgate-filter-output -j ACCEPT
fi

exit 0
