#!/bin/sh

CONFIG=/bin/config
PROG=/bin/openvpn
mtdn=`grep cert /proc/mtd | awk -F ':' '{print $1}' | awk -F 'd' '{print $2}'`
partion=/dev/mtd$mtdn
OPENVPN_CONF_DIR=/tmp/openvpn/
EASY_RSA_DIR=/tmp/etc/easy-rsa

generate_server_conf_file() {
	if [ "$1" = "tap" ]; then
	port=$($CONFIG get vpn_serv_port)
	proto=$($CONFIG get vpn_serv_type)
	if [ "$proto" = "udp" ]; then
		sndbuf=393216
		rcvbuf=393216
	else
		sndbuf=0
		rcvbuf=0
	fi
	cat <<EOF
dh /tmp/openvpn/dh1024.pem
ca /tmp/openvpn/ca.crt
cert /tmp/openvpn/server.crt
key /tmp/openvpn/server.key
dev tap0
server-bridge nogw
proto $proto 
port $port 
keepalive 10 120
verb 0
mute 5
log-append /tmp/openvpn_log
writepid /tmp/openvpnd.pid
status /tmp/openvpnd.status 5
mtu-disc yes
topology subnet
script-security 2
cipher AES-128-CBC
auth sha1
tls-server
client-to-client
duplicate-cn
comp-lzo
fast-io
client-connect "/tmp/openvpn/push_routing_rule tap"
sndbuf $sndbuf
rcvbuf $rcvbuf
EOF
	else 
	port=$($CONFIG get tun_vpn_serv_port)
	proto=$($CONFIG get tun_vpn_serv_type)
	lan_netmask=$($CONFIG get lan_netmask)
	lan_ipaddr=$($CONFIG get lan_ipaddr)
	subnet=$(tun_net $lan_ipaddr $lan_netmask)
	wanifname=$($CONFIG get wan_ifname)
	wannetwork=$(ip addr show $wanifname|grep "inet\b"|awk '{print $2}')
	waninfo=$(ipcalc.sh ${wannetwork%%/*} ${wannetwork#*/})
	eval $waninfo
	if [ "$NETWORK" = "$subnet" ]; then
		subnet=$(tun_net $IP $NETMASK)
	fi
	if [ "$proto" = "udp" ]; then
		sndbuf=393216
		rcvbuf=393216
	else
		sndbuf=0
		rcvbuf=0
	fi
	cat <<EOF
dh /tmp/openvpn/dh1024.pem
ca /tmp/openvpn/ca.crt
cert /tmp/openvpn/server.crt
key /tmp/openvpn/server.key
server $subnet 255.255.255.0
dev tun0
proto $proto 
port $port 
keepalive 10 120
verb 0
mute 5
log-append /tmp/openvpn_tun_log
writepid /tmp/openvpnd_tun.pid
status /tmp/openvpnd_tun.status 5
mtu-disc yes
topology subnet
script-security 2
cipher AES-128-CBC
auth sha1
client-to-client
duplicate-cn
comp-lzo
fast-io
push "dhcp-option DNS $lan_ipaddr"
client-connect "/tmp/openvpn/push_routing_rule tun"
sndbuf $sndbuf
rcvbuf $rcvbuf
EOF
	fi
}

set_up_ethernet_bridge() {
	br="br0"
	tap="tap0"
	lan_ipaddr=$($CONFIG get lan_ipaddr)
	lan_netmask=$($CONFIG get lan_netmask)
	$PROG --mktun --dev $tap
	brctl addif $br $tap
	ifconfig $tap 0.0.0.0 promisc up
	ifconfig $br $lan_ipaddr netmask $lan_netmask 
	
}

extract_cert_file() {
	mkdir -p $OPENVPN_CONF_DIR

	nanddump -q $partion -f  /tmp/openvpn_keys.tar.gz
	tar -xzvf /tmp/openvpn_keys.tar.gz -C $OPENVPN_CONF_DIR
	TAR_STATUS=$?
	if [ -s $OPENVPN_CONF_DIR/cert.info  -a -s $OPENVPN_CONF_DIR/ca.crt -a -s $OPENVPN_CONF_DIR/dh1024.pem -a -s $OPENVPN_CONF_DIR/client.crt -a -s $OPENVPN_CONF_DIR/client.key -a -s $OPENVPN_CONF_DIR/server.crt -a -s $OPENVPN_CONF_DIR/server.key ]; then
		FILES_EXIST=1
	fi
	if [ "$TAR_STATUS" = "0" -a "$FILES_EXIST" = "1" ]; then
		RET_STATUS=0
	else
		RET_STATUS=1
		rm -f $OPENVPN_CONF_DIR/*
	fi	   
	rm -f /tmp/openvpn_keys.tar.gz
	echo $RET_STATUS > $OPENVPN_CONF_DIR/cert_file_status
	cp /etc/openvpn/push_routing_rule $OPENVPN_CONF_DIR
	return $RET_STATUS
}

write_back_to_partion(){
	cd $EASY_RSA_DIR/keys
	CERT_FILE="cert.info ca.crt dh1024.pem client.crt client.key server.crt server.key" 

	tar -czvf openvpn_keys.tar.gz $CERT_FILE
	#dd if=/dev/zero bs=1024k count=1 | tr "\000" "\377" >1024kdata
	#dd if=openvpn_keys.tar.gz of=1024kdata conv=notrunc
	#flash_erase $partion 0 0
	#cat 1024kdata > $partion
	flash_erase $partion 0 0
	nandwrite -p -m -q $partion openvpn_keys.tar.gz
	
	cp $CERT_FILE $OPENVPN_CONF_DIR
}

regenerate_cert_file() {
	local date_yy=$(date |awk -F ' ' '{printf $NF}')
	if [ $date_yy -eq 1970 ]; then
		/bin/openvpn_update
		return
	fi
	mkdir -p $EASY_RSA_DIR
	cp /etc/easy-rsa/openssl*.cnf $EASY_RSA_DIR

	#Temporay Code for BCM cannot read sn, disable cert check, remove if partition is ok
	if [ -z $(artmtd -r sn | grep sn: | sed 's/sn://g') ]; then
		echo "Openvpn.init: cannot read sn, skip generate cert"
		return
	fi

	#Save the generate cert pid to void double calling
	[ ! -d /var/run/ ] && mkdir -p /var/run/
	echo $$ > /var/run/openvpn_generate_cert.pid

	clean-all
	build-ca
	build-key-server server
	if [ -f /tmp/md5vpn ] && [ -f /tmp/openvpn/dh1024.pem ] && [ -n "`cat /tmp/openvpn/dh1024.pem`" ]; then
		cp /tmp/openvpn/dh1024.pem $EASY_RSA_DIR/keys/
	else
		build-dh
	fi
	build-key client
	# input: artmtd -r sn
	# output: sn:3V01475S00025
	#         SN: 3V01475S00025
	sn=$(artmtd -r sn | grep sn: | sed 's/sn://g')
	echo $sn > $EASY_RSA_DIR/keys/cert.info
	write_back_to_partion

	echo -n > /var/run/openvpn_generate_cert.pid
}

boot() {
	extract_cert_file || {
		echo "extract vpn cert file fail, can not start vpn server" >/dev/console
		exit 1
	}	
	start
}

start() {
	if [ "$($CONFIG get vpn_enable)" = "0" ]; then
		exit 1
	fi
	if [ "$($CONFIG get endis_ddns)" = "0" ] && [ "$($CONFIG get wan_proto)" != "static" ] && [ "$($CONFIG get wan_pppoe_wan_assign)" = "0" ]; then
		exit 1
	fi
	if [ "$($CONFIG get ap_mode)" = "1" ]; then
		exit 1
	fi

	[ -d /tmp/openvpn ] || extract_cert_file
	OPENVPN_TAP_CONF_FILE=/tmp/openvpn/server_tap.conf
	OPENVPN_TUN_CONF_FILE=/tmp/openvpn/server_tun.conf

	generate_server_conf_file tap > $OPENVPN_TAP_CONF_FILE
	generate_server_conf_file tun > $OPENVPN_TUN_CONF_FILE

    	set_up_ethernet_bridge

	# open the door to let client in 
	$CONFIG set vpn_tun_ip_for_gui=${subnet}
	$CONFIG set vpn_tun_server_ip=${subnet}
	net-wall rule
	net-wall start

	$PROG $OPENVPN_TAP_CONF_FILE &
	$PROG $OPENVPN_TUN_CONF_FILE &

	/usr/bin/wget -T 10 http://www.speedtest.net/api/country -O /tmp/openvpn/server_location
}

stop() {
	br="br0"
	tap="tap0"

	kill `cat /tmp/openvpnd.pid` 
	rm -f /tmp/openvpnd.pid
	kill `cat /tmp/openvpnd_tun.pid`
	rm -f /tmp/openvpnd_tun.pid

	brctl delif $br $tap
	$PROG --rmtun --dev $tap

	#close the door
	net-wall rule
	net-wall start
}

restart() {
	stop
	start
}

case "$1" in
	"boot")
		boot
	;;
	"start")
		start
	;;
	"stop")
		stop
	;;
	"restart")
		restart
	;;
	"regenerate_cert_file")
		regenerate_cert_file
	;;
	*)
		echo "Unknow command" > /dev/console
		echo "Usage: $0 boot|start|stop|restart|regenerate_cert_file" > /dev/console
	;;
esac
