#!/bin/sh

#shell script infomation
ME=ppp-hb
FP=/usr/bin/$ME

USAGE(){
cat <<EOF5
$ME script manages half bridge modes
usage:
$FP command [mandatory parameters] <optional switches [mandatory parameters]>

command:
start	sets up half-bridge mode scripts to run on IP change
stop	exits and disables half-bridge mode

switch:
<-c [name]>	Connection ID - auto detects defaults to connection0
<-d>		diag var save
<-3g>		3g mode (same ip and gateway for 3g)
<-sgw>		Spoof ISP Gateway uses default Netmask 255.255.255.0
<-lif [name]>	Lan interface name - auto detects default br0
<-mgw>		Use modem IP as gateway in LAN dhcp
<-nm [mask]>	Forced Netmask in form 255.255.255.255 (default)
<-nodhcp>	Do not use dhcpd - only use if IP static!
<-nonat>	Disable nat, but leave firewall
<-nofw>		Completely disable iptables netfilter firewall, default is not to change Web GUI config
<-s [value]>	Start delay in seconds on first call to allow log time to update etc
<-t [value]>	Short lease time in seconds used when no WAN IP default 30 seconds
		Lease time used when WAN UP is as initially defined in Web GUI
<-v>		verbose logging of iptables, route and ifconfig commands
EOF5
}

#commands outside /bin
IFC=/sbin/ifconfig
IPT=/sbin/iptables
RTE=/sbin/route
KIL=/bin/killall
UPD=/usr/sbin/udhcpd
LGR=/bin/logger

#system files
UPS=/etc/ppp/ip-up
DNS=/etc/ppp/ip-down
OCF=/var/tmp/udhcpd.conf

#temp files
TMP=/tmp/
VAR="$TMP"vars.sh
EXT="$TMP"undo.sh
DCF="$TMP"default.conf
NCF="$TMP"dhcpd.conf
SHB='#!/bin/sh'


#functions
LG(){
	echo "$ME: $@"|$LGR -s
}

EX(){
	LG "Error - $@, exiting"
	exit 1
}

#CL options
#defaults from previous call
if [ -x "$VAR" ];then
	. $VAR
else # non null defaults
	DP=1;FW=1;LIF=br0;STATE=0
fi

#default command
CM=HP

#Command Line over-rides stored options
while [ "$1" ]; do
    case $1 in
	start)	#[ "$STATE" != "0" ]&& exit 1
		CM=IT
		shift;continue;;
	stop)	[ "$STATE" = "0" ]&& EX "not enabled"
		CM=EXI
		shift;continue;;
	-3g)	#[ "$STATE" != "0" ]&& exit 1
		CM=3G_IT
		shift;continue;;
	-c)	CON="$2";LG "CONnection" $CON
		shift 2;continue;;
	-d)	DBG=1;LG "Saving all vars on clean exit"
		shift;continue;;
	-sgw)	SGW=1;SNM=1;LG "Spoof GateWay"
		shift;continue;;
	-lif)	LIF="$2";LG "Lan InterFace:" $LIF
		shift 2;continue;;
	-mgw)	MGW=1;LG "Modem IP as GateWay"
		shift;continue;;
	-nonat)	NNT="1";LG "NoNaT config"
		shift;continue;;
	-nm)	NM="$2";SNM=1;LG "NetMask:" $NM
		shift 2;continue;;
	-s)	SD="$2";LG "Start Delay:" $SD
		shift 2;continue;;
	-t)	SL="$2";LG "Short Lease Time:" $SL
		shift 2;continue;;
	-v)	VB=1;LG "VerBose logging enabled"
		shift;continue;;
	-nofw)	FW="";LG "No Firewall"
		shift;continue;;
	-nodhcp)	DP="";LG "No dhcp"
		shift;continue;;
	*)	CM=HP;LG "Unknown option:" $1
		shift;continue;;
	esac
done
echo "command: $CM"


#Check for compatible options
[ "$SGW" ]&&[ -z "$FW" ]&& EX "Gateway spoof needs iptables"
[ -z "$FW" ]&& NNT=1

#ACTION MACROS

#restart udhcpd
UDH(){
	[ "$(ps|grep [u]dhcpd)" ]&& $KIL udhcpd
	$UPD $1 >/dev/null &
	LG "udhcpd started with conf" $1
}

#create single IP dhcpd conf file
CNF(){
	cat >$1<<EOF3
start $2
end $2
interface $LIF
opt router $3
opt subnet $4
lease_file      /var/run/udhcpd.leases  #defualt: /var/lib/misc/udhcpd.leases
pidfile /var/run/udhcpd.pid      #default: /var/run/udhcpd.pid
max_leases	101
$(cat /etc/resolv.conf|while read n d; do echo "opt dns $d";done)
EOF3
}

#parse dhcpd conf
PRS(){
	x=$(cat $OCF|grep "$2")
	x="${x##* }"
	[ -z "$x" ]&& EX "Unable to parse $2"
	eval $1="$x"
}

# create default dhcpd conf
DEFCNF(){

#check read  web  LAN dhcp config
	[ ! -r "$OCF" ]&& EX "Unable to read $OCF"
#client IP
	PRS LIP start
#modem IP
	PRS MIP router
#LAN Mask
	PRS LNM subnet
#LAN i/f
	PRS LIF interface
#lease time from web gui
	PRS LT "opt lease"
#re-use same lease_file
	PRS LF lease_file
#create new default dhcp conf file
	CNF $DCF $LIP $MIP $LNM ${SL:=30}
	STATE=2
}

#Function to save current state and turn off CLI controlled utils
CLX(){
	echo "$1=$(echo $1|$CLI)">>$EXT
	echo "begin;$1=0;end"|$CLI
}

#function to  config core functions
CFG(){

#if not provided from command line try to find connection id
	if [ -z "$CON" ];then
		x=$(echo "upnp:settings/connection"|$CLI)
		x="${x%% *}"
		CON=${x:=connection0}	#default
	fi
#Start undo script
	cat >$EXT<<EOF4
$SHB
#undo file to restore original router state when exiting $FP
$CLI <<EOF
begin
EOF4
#default to leave firewall as defined in web -
	if [ "$FW" ];then
#just turn off NAT
		CLX "$CON:fwan:settings/private/nat/state"
	else
#completely turn off iptables netfilter
		CLX "fdb:settings/service/nat/state"
	fi
#disable  DHCPD
	[ "$DP" ]&& CLX "landhcps0:settings/state"
#disable upnp needs IP on ppp0
	CLX "upnp:settings/state"
#and if no nat ,DPROXY,SNTP,DDNS,UPNP
	if [ "$NNT" ];then
		CLX "dproxy:settings/state"
		CLX "sntp:settings/status"
		if echo "logic:status/nspver"|$CLI |grep 3.7;then
			x=client
		else	
			x=""
		fi
		DDNS=ddns$x:settings/$CON
		CLX "$DDNS/dyndns/state"
		CLX "$DDNS/noip/state"
		CLX "$DDNS/tzo/state"
		CLX "$DDNS/dnsomatic/state"
	fi
#Finish undo file
	echo -e "end\nEOF">>$EXT; chmod +x $EXT
	STATE=3	#CONFIGURED
}
#iptables
IP(){
	[ "$VB" ]&& LG "$IPT $@"
	$IPT "$@"
}

#route
RT(){
	[ "$VB" ]&& LG "$RTE $@"
	$RTE "$@"
}

#ifconfig
IC(){
	[ "$VB" ]&& LG "$IFC $@"
	$IFC $@
}

#Macro for H-B IP UP called on wanup or if init and WAN already up
HBUP(){

#remove ISP supplied address from ppp0
	IC ${WIF:=ppp0} 0.0.0.0

#Spoof GW
	if [ "$SGW" ];then
		a="${WIP##*.}"
		if [ "$a" = "254" ];then
			b=253
		else

#set SGW next to IP
			let b=$a/2*2
			[ "$b" = "$a" ]&& let b=$a+1
		fi
		SGW="${WIP%.*}.$b"
		LG "Spoofed Gateway is $SGW Netmask ${NM:=255.255.255.0}"
	fi

#create new udhcpd conf file
	if [ "$DP" ];then
		CNF $NCF $WIP ${TGW:-$GW} ${NM:=$MK} $LT

#restart dhcpd with new config
		UDH $NCF
	fi

#Tell modem to find the WAN IP via br0
	RT add -host $WIP dev $LIF

#GW via ppp0
	RT add -host $GW dev $WIF
	RT add default gw $GW

#enable proxy arp which allows modem to answer arp requests for the ISP GW etc on the LAN i/f
	echo "1" >/proc/sys/net/ipv4/conf/$WIF/proxy_arp
	echo "1" >/proc/sys/net/ipv4/conf/$LIF/proxy_arp

#spoofed net
	if [ "$SNM" ];then

#calculate spoofed subnet
		a="${WIP%.*}";b="${WIP#*.}";n="${NM%.*}";m="${NM#*.}"
		SNW=$((${WIP%%.*}&${NM%%.*})).$((${b%%.*}&${m%%.*})).$((${a##*.}&${n##*.})).$((${WIP##*.}&${NM##*.}))
		RT add -net $SNW netmask $NM dev $WIF
	fi

#divert spoof GW to real one
	[ "$SGW" ]&& IP -t nat -I PREROUTING -i $LIF -d $SGW -j DNAT --to $GW
}

HBUP_3G(){

#remove ISP supplied address from ppp0
        IC ${WIF:=usbnet0} 0.0.0.0

#GW = WIP + 1
	a=$((${WIP##*.}+1))
	GW="${WIP%.*}.$a"

	FAKEGW=$WIP

#create new udhcpd conf file
        if [ "$DP" ];then
                CNF $NCF $WIP ${TGW:-$FAKEGW} ${NM:=$MK} $LT

#restart dhcpd with new config
                UDH $NCF
        fi

#Set IP for usbnet
	IC $WIF $GW netmask 255.255.255.255

#Tell modem to find the WAN IP via br0
        RT add -host $WIP dev $LIF

#GW via usbnet0

        RT add default dev $WIF

#enable proxy arp which allows modem to answer arp requests for the ISP GW etc on the LAN i/f
        echo "1" >/proc/sys/net/ipv4/conf/$WIF/proxy_arp
        echo "1" >/proc/sys/net/ipv4/conf/$LIF/proxy_arp
}


#Macro for HB IP-DN called when wan goes down or exiting
HBDN(){

#delete old routing and firewall rules
	[ "$SNW" ]&& RT del -net $SNW netmask $NM dev $WIF
	RT del -host $WIP dev $LIF
	RT del -host $GW dev $WIF

	#restart pppoe
	/usr/bin/pppoe-action restart

}

#called on ppp up or if init and WAN already up
WANUP(){

	if [ "$SD" -gt "0" ];then
		LG "Pausing for $SD seconds as requested"
		sleep $SD;SD=0
	fi

#if not already done configure
	if [ "$STATE" -lt "3" ];then
		LG "Configuring, please wait..."
		CFG
#read ISP supplied info from ifconfig ppp0 information string - may have changed since we were called
		x=$($IFC $WIF|grep inet)
		MK=${x#*k:}
		x=${x#*r:};WIP=${x%% *}
		x=${x#*P:};GW=${x%% *}
	fi
	HBUP
	STATE=4	#RUNNING
}

#called on ppp up or if init and WAN already up
WANUP_3G(){

        if [ "$SD" -gt "0" ];then
                LG "Pausing for $SD seconds as requested"
                sleep $SD;SD=0
        fi

#if not already done configure
        if [ "$STATE" -lt "3" ];then
                LG "Configuring, please wait..."
                CFG
#read ISP supplied info from ifconfig ppp0 information string - may have changed since we were called
                x=$($IFC $WIF|grep inet)
                MK=${x#*k:}
                x=${x#*r:};WIP=${x%% *}
                x=${x#*P:};GW=${x%% *}
        fi
        HBUP_3G
        STATE=4 #RUNNING
}


# Execute commands

case $CM in

IT)
	STATE=1	#INITIALIZED

#get name of WAN I/F ppp0?,  if it exists go straight in
	x=$($IFC|grep Point)
	WIF="${x%% *}"
	[ "$WIF" ]&& WANUP
;;

3G_IT)
        STATE=1 #INITIALIZED

#get name of WAN I/F USBNET0,  if it exists go straight in
	x=$($IFC|grep usbnet0)
	WIF="${x%% *}"
        [ "$WIF" ]&& WANUP_3G
;;

UP)
	WANUP
;;

DN)
#DOWN
	HBDN
#no connection so revert to default dhcp - no delay
	[ "$STATE" -gt "1" ]&&[ "$DP" ]&& UDH $DCF
;;

EXI)

#disable  scripts
	#return modem functionality if in half-bridge
	if [ "$STATE" -gt "3" ];then
		HBDN
		[ "$DP" ]&& UDH /etc/udhcpd.conf
		if [ -x "$EXT" ];then
			. $EXT
		fi
	fi
	
        echo "0" >/proc/sys/net/ipv4/conf/$WIF/proxy_arp                                           
        echo "0" >/proc/sys/net/ipv4/conf/$LIF/proxy_arp

	STATE=0
	
	LG "Half Bridge Mode Finished"
	exit
;;

HP)
	USAGE
	EX "Nothing to do"
;;

*) EX "Invalid Command, I should never get here!"
;;

esac

#Clean exit save vars
x(){
	eval a=\$$1
	[ "$a" ]&& echo $1=$a>>$VAR
}
echo "#Saved Vars for $FP">$VAR
x CM
x STATE
x WIP
x MK
x GW
x SNM
x NM
x SGW
x SNW
x WIF
x CON

x MIP
x LNM
x LIF

x LIP
x MGW
x LF
x LT
x SL
x SD

x FW
x NNT
x DP
x DBG
x VB

[ "$DBG" ]&& set >>$VAR
chmod +x $VAR
exit
