#!/bin/sh

#
# Here, you can find the variables that you have to change.
#

# enable this for debugging
LOG_DEBUG=0

# number of cluster node (must be unique, from 1 to N)
NODE=1
# number of nodes that belong this cluster
TOTAL_NODES=2

# this is the real MAC address of eth1
REAL_HWADDR1=00:18:71:68:f2:34

# this is the real MAC address of eth2
REAL_HWADDR2=00:11:0a:60:e7:32

#
# This below shouldn't change for this example script.
#

# this is the cluster multicast MAC address of eth1
MC_HWADDR1=01:00:5e:00:01:01

# this is the cluster multicast MAC address of eth2
MC_HWADDR2=01:00:5e:00:01:02

# cluster IP address of eth1
ADDR1=192.168.0.5/24

# cluster IP address of eth2
ADDR2=192.168.1.5/24

# random seed: it has to be the same in both nodes
SEED=0xdeadbeef

start_cluster_address()
{
	# set cluster IP addresses
	ip a a $ADDR1 dev eth1
	ip a a $ADDR2 dev eth2
	# set cluster multicast MAC addresses
	ip maddr add $MC_HWADDR1 dev eth1
	ip maddr add $MC_HWADDR2 dev eth2
	# mangle ARP replies to include the cluster multicast MAC addresses
	arptables -I OUTPUT -o eth1 --h-length 6 \
		-j mangle --mangle-mac-s $MC_HWADDR1
	# mangle ARP request to use the original MAC address (otherwise the
	# stack drops this packet).
	arptables -I INPUT -i eth1 --h-length 6 --destination-mac \
		$MC_HWADDR1 -j mangle --mangle-mac-d $REAL_HWADDR1
	arptables -I OUTPUT -o eth2 --h-length 6 \
		-j mangle --mangle-mac-s $MC_HWADDR2
	arptables -I INPUT -i eth2 --h-length 6 --destination-mac \
		$MC_HWADDR2 -j mangle --mangle-mac-d $REAL_HWADDR2
}

stop_cluster_address()
{
	# delete cluster IP addresses
	ip a d $ADDR1 dev eth1
	ip a d $ADDR2 dev eth2
	# delete cluster multicast MAC addresses
	ip maddr del $MC_HWADDR1 dev eth1
	ip maddr del $MC_HWADDR2 dev eth2
	# delete ARP replies mangling 
	arptables -D OUTPUT -o eth1 --h-length 6 \
		-j mangle --mangle-mac-s $MC_HWADDR1
	# delete ARP requests mangling
	arptables -D INPUT -i eth1 --h-length 6 --destination-mac \
		$MC_HWADDR1 -j mangle --mangle-mac-d $REAL_HWADDR1
	arptables -D OUTPUT -o eth2 --h-length 6 \
		-j mangle --mangle-mac-s $MC_HWADDR2
	arptables -D INPUT -i eth2 --h-length 6 --destination-mac \
		$MC_HWADDR2 -j mangle --mangle-mac-d $REAL_HWADDR2
}

start_nat()
{
	iptables -A POSTROUTING -t nat -s 192.168.0.11 \
		-j SNAT --to-source 192.168.1.5 
	iptables -A POSTROUTING -t nat -s 192.168.0.2 \
		-j SNAT --to-source 192.168.1.5 
}

stop_nat()
{
	iptables -D POSTROUTING -t nat -s 192.168.0.11 \
		-j SNAT --to-source 192.168.1.5 
	iptables -D POSTROUTING -t nat -s 192.168.0.2 \
		-j SNAT --to-source 192.168.1.5 
}

case "$1" in
start)
	echo "starting cluster configuration for node $NODE."

	# just in case that you forget it
	echo 1 > /proc/sys/net/ipv4/ip_forward

	# disable TCP pickup
	echo 0 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal
	echo 0 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_loose

	start_cluster_address
	start_nat

	# drop new and invalid flows from eth2 (not allowed)
	iptables -A PREROUTING -t mangle -i eth2 \
		-m state --state NEW,INVALID -j DROP

	# mark packets that belong to this node (go direction)
	iptables -A PREROUTING -t mangle -i eth1 -m cluster \
		--cluster-total-nodes $TOTAL_NODES --cluster-local-node $NODE \
		--cluster-hash-seed $SEED -j MARK --set-mark 0xffff

	# mark packet that belong to this node (reply direction)
	# note: we *do* need this to change the packet type to PACKET_HOST,
	# otherwise the stack silently drops the packet.
	iptables -A PREROUTING -t mangle -i eth2 -m cluster \
		--cluster-total-nodes $TOTAL_NODES --cluster-local-node $NODE \
		--cluster-hash-seed $SEED -j MARK --set-mark 0xffff

	if [ $LOG_DEBUG -eq 1 ]
	then
		iptables -A PREROUTING -t mangle -i eth1 -m mark \
			--mark 0xffff -j LOG --log-prefix "cluster-accept: "
		iptables -A PREROUTING -t mangle -i eth1 -m mark \
			! --mark 0xffff -j LOG --log-prefix "cluster-drop: "
		iptables -A PREROUTING -t mangle -i eth2 -m mark \
			--mark 0xffff \
			-j LOG --log-prefix "cluster-reply-accept: "
		iptables -A PREROUTING -t mangle -i eth2 -m mark \
			! --mark 0xffff \
			-j LOG --log-prefix "cluster-reply-drop: "
	fi

	# drop packets that don't belong to us (go direction)
	iptables -A PREROUTING -t mangle -i eth1 -m mark \
		! --mark 0xffff -j DROP

	# drop packets that don't belong to us (reply direction)
	iptables -A PREROUTING -t mangle -i eth2 -m mark \
		! --mark 0xffff -j DROP
	;;
stop)
	echo "stopping cluster configuration for node $NODE."

	stop_cluster_address
	stop_nat

	# drop new and invalid flows from eth2 (not allowed)
	iptables -D PREROUTING -t mangle -i eth2 \
		-m state --state NEW,INVALID -j DROP

	iptables -D PREROUTING -t mangle -i eth1 -m cluster \
		--cluster-total-nodes $TOTAL_NODES --cluster-local-node $NODE \
		--cluster-hash-seed $SEED -j MARK --set-mark 0xffff

	iptables -D PREROUTING -t mangle -i eth2 -m cluster \
		--cluster-total-nodes $TOTAL_NODES --cluster-local-node $NODE \
		--cluster-hash-seed $SEED -j MARK --set-mark 0xffff

	if [ $LOG_DEBUG -eq 1 ]
	then
		iptables -D PREROUTING -t mangle -i eth1 -m mark \
			--mark 0xffff -j LOG --log-prefix "cluster-accept: "
		iptables -D PREROUTING -t mangle -i eth1 -m mark \
			! --mark 0xffff -j LOG --log-prefix "cluster-drop: "
		iptables -D PREROUTING -t mangle -i eth2 -m mark \
			--mark 0xffff \
			-j LOG --log-prefix "cluster-reply-accept: "
		iptables -D PREROUTING -t mangle -i eth2 -m mark \
			! --mark 0xffff \
			-j LOG --log-prefix "cluster-reply-drop: "
	fi

	iptables -D PREROUTING -t mangle -i eth1 -m mark \
		! --mark 0xffff -j DROP

	iptables -D PREROUTING -t mangle -i eth2 -m mark \
		! --mark 0xffff -j DROP
	;;
*)
	echo "$0 start|stop"
	;;
esac
