#!/bin/bash
# common functions for 'wdog' scripts
#
# Copyright (c) 2013-2017, Parallels International GmbH
#
# Our contact details: Parallels International GmbH, Vordergasse 59, 8200
# Schaffhausen, Switzerland.
#

IPv4TABLES_BIN="/sbin/iptables"
IPv6TABLES_BIN="/sbin/ip6tables"
ARPTABLES_BIN="/sbin/arptables"

# ports 2510 and 2511 are the defaults for pstorage MDSD
ALLOWED_TCP_PORTS="ssh 2510 2511"

# Get list of node's IP addresses
IP_ADDRESSES=$(/sbin/ip address list | sed "s/[[:blank:]]\+/ /g" | egrep -v "lo$" | awk -F '[ /]' '/ inet / {print $3}')


# Check if IPv6tables are operable
/sbin/modprobe ip6table_filter > /dev/null 2>&1
if [ $? -eq 0 -a -x "${IPv6TABLES_BIN}" ]; then
        ipv6_enabled=1;
else
        ipv6_enabled=0;
fi


# Fill $IPTABLES_BIN variable with a path either to iptables or to ip6tables binary
# Takes protocol version as an argument - either "4" or "6".
function set_iptables_bin_vX()
{
	if [ $1 -eq 4 ]; then 
		IPTABLES_BIN=${IPv4TABLES_BIN} 
	else 
		IPTABLES_BIN=${IPv6TABLES_BIN}
	fi
}


# Create iptables traffic-blocking rules for X protocol
# Takes protocol version as an argument - either "4" or "6".
function add_iptables_vX()
{
	set -e

	set_iptables_bin_vX $1

	${IPTABLES_BIN} -N WDOG_CHAIN_IN
	${IPTABLES_BIN} -N WDOG_CHAIN_OUT

	# make a whitelist for allowed TCP connections
	for port in ${ALLOWED_TCP_PORTS}; do
		${IPTABLES_BIN} -A WDOG_CHAIN_IN -p tcp --dport ${port} -j RETURN
		${IPTABLES_BIN} -A WDOG_CHAIN_IN -p tcp --sport ${port} -j RETURN
		${IPTABLES_BIN} -A WDOG_CHAIN_OUT -p tcp --dport ${port} -j RETURN
		${IPTABLES_BIN} -A WDOG_CHAIN_OUT -p tcp --sport ${port} -j RETURN
	done

	${IPTABLES_BIN} -A WDOG_CHAIN_IN -j DROP
	${IPTABLES_BIN} -A WDOG_CHAIN_OUT -j DROP

	# and drop all the rest packages
	${IPTABLES_BIN} -I INPUT   --match wdog_tmo -j WDOG_CHAIN_IN
	${IPTABLES_BIN} -I FORWARD --match wdog_tmo -j DROP
	${IPTABLES_BIN} -I OUTPUT  --match wdog_tmo -j WDOG_CHAIN_OUT
}


# Add traffic-blocking iptables rules for all protocols
# Does not take arguments
function add_iptables_rules() 
{
	set -e

	add_iptables_vX 4
	[ $ipv6_enabled -eq 1 ] && add_iptables_vX 6

	echo 1 > /proc/sys/net/bridge/bridge-nf-call-arptables
}


# Add ARP and NDP filtering rules for all protocols
function add_arptables_ndp_rules()
{
	set -e

	# Block arp requests directed to VEs to avoid network collision due to VE relocation
	$ARPTABLES_BIN -N WDOG_CHAIN_ARP_FWD
	$ARPTABLES_BIN -A WDOG_CHAIN_ARP_FWD -j DROP
	$ARPTABLES_BIN -I FORWARD -m wdog_tmo -j WDOG_CHAIN_ARP_FWD
	$ARPTABLES_BIN -I INPUT -m wdog_tmo -j WDOG_CHAIN_ARP_FWD

	# ARP requests to node's IP addresses must be accepted to make sure node is still accessible by SSH
	for IPADDR in ${IP_ADDRESSES}; do
		$ARPTABLES_BIN -I WDOG_CHAIN_ARP_FWD -d ${IPADDR} -j RETURN
	done

	# IPv6 does not use ARP, instead it uses Neighbor Discover Protocol which utilizes ICMPv6
	if [ $ipv6_enabled -eq 1 ]; then
		$IPv6TABLES_BIN -I WDOG_CHAIN_IN -p icmpv6 -j RETURN
		$IPv6TABLES_BIN -I WDOG_CHAIN_OUT -p icmpv6 -j RETURN
	fi

}


# Clean iptables traffic-blocking rules established by watchdog for X protocol
# Takes protocol version as an argument - either "4" or "6".
function clean_iptables_vX()
{
	set_iptables_bin_vX $1

	${IPTABLES_BIN} -F WDOG_CHAIN_IN
	${IPTABLES_BIN} -F WDOG_CHAIN_OUT

	${IPTABLES_BIN} -D FORWARD -j DROP -m wdog_tmo

	${IPTABLES_BIN} -D INPUT -j WDOG_CHAIN_IN -m wdog_tmo
	${IPTABLES_BIN} -D OUTPUT -j WDOG_CHAIN_OUT -m wdog_tmo

	${IPTABLES_BIN} -X WDOG_CHAIN_IN
	${IPTABLES_BIN} -X WDOG_CHAIN_OUT
}


# Clean traffic-blocking iptables rules established by watchdog for all protocols
# Does not take arguments
function clean_ip() 
{
	clean_iptables_vX 4
	[ $ipv6_enabled -eq 1 ] && clean_iptables_vX 6

	echo 0 > /proc/sys/net/bridge/bridge-nf-call-arptables
}


# Clean ARP and NDP blocking rules established by watchdog
# Does not take arguments
function clean_arp()
{
	$ARPTABLES_BIN -F WDOG_CHAIN_ARP_FWD
	$ARPTABLES_BIN -D FORWARD -j WDOG_CHAIN_ARP_FWD -m wdog_tmo
	$ARPTABLES_BIN -D INPUT -j WDOG_CHAIN_ARP_FWD -m wdog_tmo
	$ARPTABLES_BIN -X WDOG_CHAIN_ARP_FWD

	if [ $ipv6_enabled -eq 1 ]; then
		${IPv6TABLES_BIN} -D WDOG_CHAIN_IN -p icmpv6 -j RETURN
		${IPv6TABLES_BIN} -D WDOG_CHAIN_OUT -p icmpv6 -j RETURN
	fi
}

# vim: noet ts=8 sts=8 sw=8
