#!/bin/sh /etc/rc.common
# Copyright (C) 2009 OpenWrt.org

NAME=sslh
PROG=/usr/sbin/sslh
START=95
PIDCOUNT=0
EXTRA_COMMANDS="killclients"
EXTRA_HELP="	killclients Kill ${NAME} processes except servers and yourself"

sslh_start()
{
	local section="$1"

	# check if section is enabled (default)
	local enabled
	config_get_bool enabled "${section}" enable 1
	[ "${enabled}" -eq 0 ] && return 1

	# increase pid file count to handle multiple instances correctly
	PIDCOUNT="$(( ${PIDCOUNT} + 1 ))"

	# prepare parameters (initialise with pid file)
	local args="-P /var/run/${NAME}.${PIDCOUNT}.pid"
	local val
	# A) listen parameter
	config_get val "${section}" listen
	[ -n "${val}" ] && append args "-p ${val}"
	# B) ssh parameter
	config_get val "${section}" ssh
	[ -n "${val}" ] && append args "-s ${val}"
	# C) ssl parameter
	config_get val "${section}" ssl
	[ -n "${val}" ] && append args "-l ${val}"
	# D) timeout (for ssh, then ssl is assumed)
	config_get val "${section}" timeout
	[ -n "${val}" ] && append args "-t ${val}"
	# E) verbose parameter
	local verbosed
	config_get_bool verbosed "${section}" verbose 0
	[ "${verbosed}" -ne 0 ] && append args "-v"

	# execute program and return its exit code
	[ "${verbosed}" -ne 0 ] && echo "${initscript}: section ${section} started via ${PROG} ${args}"
	${PROG} ${args}
	return $?
}

start()
{
	config_load "${NAME}"
	config_foreach sslh_start sslh
}

stop()
{
	local pidfile
	local rc=0

	# killing all server processes
	for pidfile in `ls /var/run/${NAME}.*.pid`
	 do
		start-stop-daemon -K -s KILL -p "${pidfile}" -n "${NAME}" >/dev/null
		[ $? -ne 0 ] && rc=1
		rm -f "${pidfile}"
	done
	[ -z "${pidfile}" ] && echo "${initscript}: no pid files, if you get problems with start then try killclients"
	[ ${rc} -ne 0 ] && echo "${initscript}: inconsistency in pid files, if you get problems with start then try killclients"
}

killclients()
{
	local ignore=''
	local server
	local pid
	local connection
	local proto
	local address

	# if this script is run from inside a client session, then ignore that session
	pid="$$"
	while [ "${pid}" -ne 0 ]
	 do
		# get parent process id
		pid=`cut -d ' ' -f 4 "/proc/${pid}/stat"`
		[ "${pid}" -eq 0 ] && break

		# check if pid is connected to a client connection
		# a) get established connection for pid
		connection=`netstat -tupn 2>/dev/null | sed "s/[ ]\+/ /g" | grep -e "ESTABLISHED ${pid}/"`
		[ -z "${connection}" ] && continue
		#    get connection details for foreign address
		proto=`echo ${connection} | cut -d ' ' -f 1`
		address=`echo ${connection} | cut -d ' ' -f 5`

		# b) get pid for foreign address, only possible if foreign address is from this machine itself
		connection=`netstat -tupn 2>/dev/null | sed "s/[ ]\+/ /g" | grep -e "^${proto}.*${address}.*ESTABLISHED.*/${NAME}"`
		[ -z "${connection}" ] && continue
		#    check that the local address (field 4) corresponds to the foreign address of the previous connection
		server=`echo ${connection} | cut -d ' ' -f 4`
		[ "${server}" != "${address}" ] && continue
		#    get pid from connection
		server=`echo ${connection} | cut -d ' ' -f 7 | cut -d '/' -f 1`

		# check if client connection
		ps | grep -e "^[ ]*${server} " | grep -e "${PROG}" >/dev/null
		if [ $? -eq 0 ]
		 then
			append ignore "${server}"
			break
		fi
	done

	# get all server pids that should be ignored
	for server in `cat /var/run/${NAME}.*.pid`
	 do
		append ignore "${server}"
	done

	# get all running pids and kill client connections
	local skip
	for pid in `pidof "${NAME}"`
	 do
		# check if correct program
		ps | grep -e "^[ ]*${pid} " | grep -e "${PROG}" >/dev/null
		[ $? -ne 0 ] && continue

		# check if pid should be ignored (servers, ourself)
		skip=0
		for server in ${ignore}
		 do
			if [ "${pid}" == "${server}" ]
			 then
				skip=1
				break
			fi
		done
		[ "${skip}" -ne 0 ] && continue

		# kill process
		echo "${initscript}: Killing ${pid}..."
		kill -KILL ${pid}
	done
}