OpenWrt Forum Archive

Topic: Need help to create UCI config and init.d script for SSLH package

The content of this topic has been archived on 16 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

Hi everybody,

I would like to create an UCI config and an init.d script for the SSH/SSL multiplexer sslh.

The structure of the UCI config itself is easy:
/etc/config/sslh

config 'sslh' 'default'
# disable or enable start of sslh
    option 'enable' '1'
# pid file is OBLIGATORY, defaults to /var/run/sslh.pid
# -P pidfile
    option 'pidfile' '/var/run/sslh.pid'
# listen defaults to 0.0.0.0:443 (all interfaces)
# -p <listenaddr>:<listenport>
    option 'listenaddr' ''
    option 'listenport' ''
# ssh defaults to localhost:22
# -s <sshhost>:<sshport>
    option 'sshhost' ''
    option 'sshport' ''
# ssl defaults to localhost:442
# -l <sslhost>:<sslport>
    option 'sslhost' ''
    option 'sslport' ''
# timeout (for ssh, then ssl is assumed) defaults to 2
# -t
    option 'timeout' ''
# verbose defaults to off
# -v
    option 'verbose' '0'

But I don't know how to read the configuration, check for obligatory values, etc. in the init.d script.
/etc/init.d/sslh (this will be updated with the progress of this thread, please read the thread for answers to your questions)

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

START=95

start()
{
  local RC=0

## load config into variables
  uci_load 'sslh'

## check parameters
# A) pid file is mandatory
  if [ -z ${CONFIG_default_pidfile} ]
   then
    echo 'sslh: pidfile not stated, but mandatory (default is /var/run/sslh.pid)'
    RC=1
  fi
# B) host and port are mandatory if one of them is stated
  local failed
# B1) listen
  failed=0
  [ ! -z ${CONFIG_default_listenaddr} ] && [   -z ${CONFIG_default_listenport} ] && failed=1
  [   -z ${CONFIG_default_listenaddr} ] && [ ! -z ${CONFIG_default_listenport} ] && failed=1
  if [ ${failed} -eq 1 ]
   then
    echo 'sslh: listen address and port must be stated'
    RC=1
  fi
# B2) ssh
  failed=0
  [ ! -z ${CONFIG_default_sshhost} ] && [   -z ${CONFIG_default_sshport} ] && failed=1
  [   -z ${CONFIG_default_sshhost} ] && [ ! -z ${CONFIG_default_sshport} ] && failed=1
  if [ ${failed} -eq 1 ]
   then
    echo 'sslh: ssh host and port must be stated'
    RC=1
  fi
# B3) ssl
  failed=0
  [ ! -z ${CONFIG_default_sslhost} ] && [   -z ${CONFIG_default_sslport} ] && failed=1
  [   -z ${CONFIG_default_sslhost} ] && [ ! -z ${CONFIG_default_sslport} ] && failed=1
  if [ ${failed} -eq 1 ]
   then
    echo 'sslh: ssl host and port must be stated'
    RC=1
  fi

## check if sslh is already running with this pid file
  if [ ! -z ${CONFIG_default_pidfile} ]
   then
    start-stop-daemon -K -t -q -p ${CONFIG_default_pidfile} -n sslh
    if [ $? -eq 0 ]
     then
      echo "sslh: already running with pidfile ${CONFIG_default_pidfile}"
      RC=1
    fi
  fi

## leave if any check failed
  [ ${RC} -ne 0 ] && return ${RC}

## check if sslh is enabled
  local enabled=0
  config_get_bool enabled 'default' 'enable' 0
  if [ ${enabled} -eq 0 ]
   then
    echo 'sslh is not enabled'
    return 1
  fi

## prepare parameters (initialise with pid file)
  local SSLHARGS="-P ${CONFIG_default_pidfile}"
#
  local option
  local added
# A) listen parameter
  option='-p'
  added=0
  if [ ! -z ${CONFIG_default_listenaddr} ]
   then
    SSLHARGS="${SSLHARGS} ${option} "
    SSLHARGS="${SSLHARGS}${CONFIG_default_listenaddr}"
    added=1
  fi
  if [ ! -z ${CONFIG_default_listenport} ]
   then
    [ ${added} -eq 0 ] && SSLHARGS="${SSLHARGS} ${option} "
    SSLHARGS="${SSLHARGS}:${CONFIG_default_listenport}"
  fi
# B) ssh parameter
  option='-s'
  added=0
  if [ ! -z ${CONFIG_default_sshhost} ]
   then
    SSLHARGS="${SSLHARGS} ${option} "
    SSLHARGS="${SSLHARGS}${CONFIG_default_sshhost}"
    added=1
  fi
  if [ ! -z ${CONFIG_default_sshport} ]
   then
    [ ${added} -eq 0 ] && SSLHARGS="${SSLHARGS} ${option} "
    SSLHARGS="${SSLHARGS}:${CONFIG_default_sshport}"
  fi
# C) ssl parameter
  option='-l'
  added=0
  if [ ! -z ${CONFIG_default_sslhost} ]
   then
    SSLHARGS="${SSLHARGS} ${option} "
    SSLHARGS="${SSLHARGS}${CONFIG_default_sslhost}"
    added=1
  fi
  if [ ! -z ${CONFIG_default_sslport} ]
   then
    [ ${added} -eq 0 ] && SSLHARGS="${SSLHARGS} ${option} "
    SSLHARGS="${SSLHARGS}:${CONFIG_default_sslport}"
  fi
# D) timeout (for ssh, then ssl is assumed)
  if [ ! -z ${CONFIG_default_timeout} ]
   then
    SSLHARGS="${SSLHARGS} -t ${CONFIG_default_timeout}"
  fi
# E) verbose parameter
  local verbosed=0
  config_get_bool verbosed 'default' 'verbose' 0
  if [ ${verbosed} -eq 1 ]
   then
    SSLHARGS="${SSLHARGS} -v"
  fi
#
  if [ ${verbosed} -eq 1 ]
   then
    echo "Starting sslh ${SSLHARGS}"
  fi

## execute command and return its exit code
  sslh ${SSLHARGS}
  RC=$?
  return ${RC}
};


stop()
{
  local RC=0

## load config into variables
  uci_load 'sslh'

## check parameters
# pid file is mandatory
  if [ -z ${CONFIG_default_pidfile} ]
   then
    echo 'sslh: pidfile not stated, but mandatory (default is /var/run/sslh.pid)'
    RC=1
  fi

## execute command and return its exit code
  start-stop-daemon -K -q -p ${CONFIG_default_pidfile} -n sslh
  RC=$?
  if [ ${RC} -eq 0 ]
   then
    rm -f ${CONFIG_default_pidfile}
  fi

  return ${RC}
};

Can somebody help or link pages that explain how to use uci config inside init.d scripts?

All help is appreciated
Maddes

(Last edited by maddes.b on 11 Jul 2009, 16:54)

Ok. We should start a course here. This program could be a good example how to make a program UCI aware. I'll post more in the next days...

That would be great.

I will try to start with something about init scripts in general:
If program (daemon) can write a pid file, then it is highly recommended to use that pid file with start-stop-daemon to end the daemon.
Always specify the name of the process when killing the daemon, to make sure that not another program gets killed, which accidentially got the process id stated in the pid file:

start-stop-daemon -K -q -p /var/run/sslh.pid -n sslh

start-stop-daemon can also be used to check if the daemon with this pid is still running, by using the test option:

start-stop-daemon -K -t -q -p /var/run/sslh.pid -n sslh
if [ $? -eq 0 ]
 then
  echo "sslh: already running with pidfile /var/run/sslh.pid"
fi

This is highly important if child processes are spawned that are required when restarting the service.
For example when restarting a SSH server, then only the main process (=listening server) should be killed and started again.
Otherwise you loose your connection and due to the killed terminal the init script will stop and does not restart the SSH server.
This way you kicked yourself out of the system.
Sometimes a web interface can help to reboot the machine, but if there are errors in the config then you may need direct access to the hardware (serial) to fix that.

(Last edited by maddes.b on 11 Jul 2009, 16:36)

Found a link with little but starting information here

Helped to find out how to read data from a UCI config file

config_load <config name>  # this will make all settings available as $CONFIG_<section>_<option>
config_get <name of return var>, <section>, <option>
config_get_bool <name of return var>, <section>, <option>, <default value if not defined or unplausible value>

There's also another thread about UCI configwith some information.

(Last edited by maddes.b on 11 Jul 2009, 16:37)

SSLH doesn't spawn any child processes and can be stopped without causing huge problems (SSH (no L) should still be available on another port from WAN or at least LAN). Therefore killing all SSLH process is ok.

Also SSLH does not allow to specify a redirection port only or an redirection address only. Always both have to be stated.
So the above checks can be removed and the options merged.

As only one instance is supported the pid file is not mandatory.

/etc/config/sslh

package 'sslh'

config 'sslh' 'default'
# disable or enable start of sslh
    option 'enable' '1'
# listen defaults to '0.0.0.0:443' (all interfaces)
# -p <listenaddr>:<listenport>
    option 'listen' ''
# ssh defaults to 'localhost:22'
# -s <sshhost>:<sshport>
    option 'ssh' ''
# ssl defaults to 'localhost:442'
# -l <sslhost>:<sslport>
    option 'ssl' ''
# pid file defaults to /var/run/sslh.pid
# -P pidfile
    option 'pidfile' ''
# timeout (for ssh, then ssl is assumed) defaults to 2
# -t
    option 'timeout' ''
# verbose defaults to off
# -v
    option 'verbose' '0'

/etc/init.d/sslh

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

NAME=sslh
PROG=/usr/sbin/${NAME}
START=95

start()
{

## load config into variables
  uci_load "${NAME}"

## check if enabled
  local enabled
  config_get_bool enabled 'default' 'enable' 0
  if [ ${enabled} -eq 0 ]
   then
    echo "${NAME} is not enabled"
    return 1
  fi

## prepare parameters (initialise with pid file)
  local ARGS=''
# A) listen parameter
  [ ! -z ${CONFIG_default_listen} ] && ARGS="${ARGS} -p ${CONFIG_default_listen}"
# B) ssh parameter
  [ ! -z ${CONFIG_default_ssh} ] && ARGS="${ARGS} -s ${CONFIG_default_ssh}"
# C) ssl parameter
  [ ! -z ${CONFIG_default_ssl} ] && ARGS="${ARGS} -l ${CONFIG_default_ssl}"
# D) pid file
  [ ! -z ${CONFIG_default_pidfile} ] && ARGS="${ARGS} -P ${CONFIG_default_pidfile}"
# E) timeout (for ssh, then ssl is assumed)
  [ ! -z ${CONFIG_default_timeout} ] && ARGS="${ARGS} -t ${CONFIG_default_timeout}"
# F) verbose parameter
  local verbosed
  config_get_bool verbosed 'default' 'verbose' 0
  [ ${verbosed} -ne 0 ] && ARGS="${ARGS} -v"
#
  [ ${verbosed} -ne 0 ] && echo "Starting ${PROG}${ARGS}"

## execute command and return its exit code
  ${PROG}${ARGS}
  return $?
}


stop()
{
  killall "${NAME}"
}

If multiple instances should be supported then duplicate pid file entries must be checked and logged (similar to the check for hosts specified for dhcp).

(Last edited by maddes.b on 11 Jul 2009, 16:46)

The discussion might have continued from here.