#!/bin/bash

# ARAnyM - bridging network
# STanda (c) 2004
#
# description: TUN/TAP driver using transparent bridge networking setup
#
# dependencies: tun module, tunctl (kernel-utils),
#               bridge module, brctl (bridge-utils)
#
# processname: arabridge 
# chkconfig: - 62 18


# source function library
# . /etc/rc.d/init.d/functions

# CHANGE THIS TO YOUR 'id'
USER=joy

TAPS=tap0
BRIDGE=br0
NIF=eth0

LOCK=/var/lock/subsys/arabridge

# make sure grep in ifconfig output works
LC_ALL=C
export LC_ALL

# defaultroute's nif
DR_NIF=$(/sbin/route -n 2>/dev/null | awk '/^0\.0\.0\.0/ {print $8}')
DEFGW=$(/sbin/route -n 2>/dev/null | awk '/^0\.0\.0\.0/ {print $2}')

# do we have the default route NIF?
DEF_ROUTE=0
if [ -n "$DR_NIF" -a "$NIF" = "$DR_NIF" -a -n "$DEFGW" ]; then
	DEF_ROUTE=1
	echo "Playing with default route at $DR_NIF with gateway to $DEFGW"
fi

success()
{
	echo "[OK]"
}

failure()
{
	echo "[FAILED]"
}

status()
{
	echo "status $1"
}

start_tap()
{
    TAP="$1"
    /sbin/ifconfig $TAP 1>/dev/null 2>/dev/null
    if [ $? -ne 0 ]; then
        echo "Creating device $TAP..."
        TAP=$(tunctl -t $TAP -u $USER)
    fi
}

case "$1" in
  start)
	echo -n "Starting TUN/TAP bridging: "

	# save the NIF name
	echo $NIF >$LOCK

	IP=$(/sbin/ifconfig $NIF | awk '/inet addr:/ {print substr($2, 6)}')
	BCAST=$(/sbin/ifconfig $NIF | awk '/inet addr:/ {print substr($3, 7)}')
	NETMASK=$(/sbin/ifconfig $NIF | awk '/inet addr:/ {print substr($4, 6)}')
	echo "NIF=$NIF IP=$IP, BCAST=$BCAST, NETMASK=$NETMASK, DEFGW=$DEFGW"

	/sbin/modprobe tun
	/sbin/modprobe bridge

	echo "Changing owner of /dev/net/tun..."
	[ -c /dev/net/tun ] && chown $USER /dev/net/tun

	echo "Setting up bridge $BRIDGE..."
	brctl addbr $BRIDGE
	brctl stp $BRIDGE off
	brctl setfd $BRIDGE 1
	brctl sethello $BRIDGE 1

	# add NIF to the bridge
	ifconfig $NIF 0.0.0.0
	brctl addif $BRIDGE $NIF 2>&1 | grep -qi "invalid"
        if [ $? -eq 0 ]; then
        	echo -n "... ERROR: wrong NIF type";
		failure; echo

		brctl delbr $BRIDGE
		rm -f $LOCK
		ifconfig $NIF $IP
		exit 1 
        fi
	echo

	# add all the tap devices
	for tap in $TAPS; do
		start_tap $tap
		brctl addif $BRIDGE $tap
		/sbin/ifconfig $tap 0.0.0.0 promisc up
	done

	# setup the bridge parameters
	/sbin/ifconfig $BRIDGE $IP netmask $NETMASK broadcast $BCAST

	# ifconfig needs to be called twice here after some delay
	# I don't really know what is going on :(
	# if not slept enough then the IP, NETMASK and BCAST setting
	# are cleared 8-| 
	sleep 1

	/sbin/ifconfig $NIF 0.0.0.0 promisc up

	# bring the bridge up
	/sbin/ifconfig $BRIDGE $IP netmask $NETMASK broadcast $BCAST up
	if [ $DEF_ROUTE -eq 0 ]; then
	   /sbin/route add default dev $BRIDGE
	   echo "adding normal route"
	else
	   /sbin/route add default dev $BRIDGE gw $DEFGW
	   echo "adding gateway route"
	fi

	echo
        success
	echo
	;;
  stop)
	echo -n "Shutting down arabridge: "

	NIF=$(cat $LOCK 2>/dev/null)
	if [ -z "$NIF" ]; then
        	echo -n "... already stopped";
		success;
		echo;
		exit 0
        fi
	echo

	IP=$(/sbin/ifconfig $BRIDGE 2>/dev/null| awk '/inet addr:/ {print substr($2, 6)}')
	BCAST=$(/sbin/ifconfig $BRIDGE 2>/dev/null| awk '/inet addr:/ {print substr($3, 7)}')
	NETMASK=$(/sbin/ifconfig $BRIDGE 2>/dev/null| awk '/inet addr:/ {print substr($4, 6)}')

	# if not slept long enough then the IP, NETMASK and BCAST setting
	# are not fetched properly 8-| 
	sleep 1

	echo "NIF=$NIF IP=$IP, BCAST=$BCAST, NETMASK=$NETMASK, DEFGW=$DEFGW"

	# bring the previous network nif back
	/sbin/ifconfig $NIF $IP netmask $NETMASK broadcast $BCAST up
	if [ $DEF_ROUTE -eq 0 ]; then
	   /sbin/route add default dev $NIF
	else
	   /sbin/route add default dev $NIF gw $DEFGW
	fi


	# get the bridge down
	/sbin/ifconfig $BRIDGE down

	for tap in $TAPS; do
		brctl delif $BRIDGE $tap
		/sbin/ifconfig $tap down
		echo
		tunctl -d $tap
	done
	brctl delbr $BRIDGE
	rm -f $LOCK
	echo
	;;
  restart)
        $0 stop
        $0 start
        ;;
  status)
        status arabridge
        ;;
  *)
	echo "Usage: arabridge {start|stop|restart|status}"
	exit 1
esac

exit 0

