Wiki:help/howtos/development/developer_information/package_development_start/webinterface_example_1

Web-interface HTTPTunnel

This example explains how to create a web-page for the package httptunnel.

Usages information:

# hts --help
Usage: hts [OPTION]... [PORT]
Listen for incoming httptunnel connections at PORT (default port is 8888).
When a connection is made, I/O is redirected to the destination specified
by the --device, --forward-port or --stdin-stdout switch.

  -c, --content-length BYTES     use HTTP PUT requests of BYTES size
                                 (k, M, and G postfixes recognized)
  -d, --device DEVICE            use DEVICE for input and output
  -F, --forward-port HOST:PORT   connect to PORT at HOST and use it for
                                 input and output
  -h, --help                     display this help and exit
  -k, --keep-alive SECONDS       send keepalive bytes every SECONDS seconds
                                 (default is 5)
  -M, --max-connection-age SEC   maximum time a connection will stay
                                 open is SEC seconds (default is 300)
  -s, --stdin-stdout             use stdin/stdout for communication
                                 (implies --no-daemon)
  -S, --strict-content-length    always write Content-Length bytes in requests
  -V, --version                  output version information and exit
  -w, --no-daemon                don't fork into the background
  -p, --pid-file LOCATION        write a PID file to LOCATION

Report bugs to bug-httptunnel@gnu.org.
#

First some characteristics of the HTTPTunnel package.

  • There is no configuration file, all arguments are options on the command line.
  • The binary (daemon) name (hts) differs from the package name (httptunnel).
  • The command line options allows to specify the PID file.

Based on the usage information we can select the following variables for inclusion in the web-interface:
-F <HOST>:<HOSTPORT>
-k <KEEPALIVE>
-M <MAXCONNECTIONAGE>
-d <DEVICE>
<CLIENTPORT>

httptunnel.cfg

Next we need to create the <package>.cfg file with the default values.
We always need the <PACKAGE>_ENABLED variable with default value 'no'.
For HOST I selected 'localhost', but I actually never used this package, so I'm not sure if this default value is good from a security point of view.

export HTTPTUNNEL_ENABLED='no'
export HTTPTUNNEL_HOST='localhost'
export HTTPTUNNEL_HOSTPORT='22'
export HTTPTUNNEL_CLIENTPORT='443'
export HTTPTUNNEL_KEEPALIVE='5'
export HTTPTUNNEL_MAXCONNECTIONAGE='300'
export HTTPTUNNEL_DEVICE=''

httptunnel.cgi

Now the <package>.cgi can be created.
The first part is Start Type and is enclosed with the sec_begin and sec_end keywords.
This part is uses the HTTPTUNNEL_ENABLED variable, and determines if the package should be started automatically at system startup.
Two input elements with radio buttons are declared within a paragraph.

On the actual web-page the first item is Status, displaying the current status of the package and a Start, Stop and Restart button. This part is probably generated by /usr/lib/libmodcgi.sh.

For each displayed text you see a lang statement and the text in both German and the English language. This lang statement is used during build on the build environment.
To be able to test your created <package>.cgi file directly on the router you can first create one without the lang statements, using just your preferred language.
After the web-interface behaves as required you can add the lang statements and the text in both languages.
See page <package>.cgi for more information on the lang statement.

The second part, enclosed with the sec_begin and sec_end keywords, is for configuring the selected parameters.
In this case a table is used with a table row (tr) for each parameter, and a column for to display the parameter name, and a column for entering the value in an input field.
A table has the advantage that the cells in the columns are automatically aligned.
In the first table data cell (td) the displays the parameter name in the correct language. The second table data cell (td) displays the current value using the Shell instruction html "$HTTPTUNNEL_<VALUE>" as value, in the input field of size characters length displayed, and a maximum of maxlength characters that can be entered.
The entered value is assigned to the input-field element name like name='<value>', which correspond to the parameter name <PACKAGE>_<VALUE>.
The input type is here always text.
After selecting the Apply button the entered values are assigned to the <PACKAGE>_<VALUE> parameters located in /mod/etc/conf/<package>.cfg.

httptunnel.cgi without lang statements:

#!/bin/sh

. /usr/lib/libmodcgi.sh

check "$HTTPTUNNEL_ENABLED" yes:auto "*":man

sec_begin 'Start type'

cat << EOF
<p>
<input id="e1" type="radio" name="enabled" value="yes"$auto_chk><label for="e1">Automatic</label>
<input id="e2" type="radio" name="enabled" value="no"$man_chk><label for="e2">Manual</label>
EOF
cat << EOF
</p>
EOF

sec_end
sec_begin 'httptunnel'

cat << EOF
<table border="0">
<tr>
	<td>Destination Host:</td>
	<td><input type="text" name="host" size="60" maxlength="255" value="$(html "$HTTPTUNNEL_HOST")"></td>
</tr>
<tr>
	<td>Destination Port:</td>
	<td><input type="text" name="hostport" size="5" maxlength="5" value="$(html "$HTTPTUNNEL_HOSTPORT")"></td>
</tr>
<tr>
	<td>Client Port:</td>
	<td><input type="text" name="clientport" size="5" maxlength="5" value="$(html "$HTTPTUNNEL_CLIENTPORT")"></td>
</tr>
<tr>
	<td>Keep Alive:</td>
	<td><input type="text" name="keepalive" size="3" maxlength="3" value="$(html "$HTTPTUNNEL_KEEPALIVE")"></td>
</tr>
<tr>
	<td>Max Connection Age:</td>
	<td><input type="text" name="maxconnectionage" size="4" maxlength="4" value="$(html "$HTTPTUNNEL_MAXCONNECTIONAGE")"></td>
</tr>
<tr>
	<td>Device:</td>
	<td><input type="text" name="device" size="10" maxlength="10" value="$(html "$HTTPTUNNEL_DEVICE")"></td>
</tr>
</table>
EOF

sec_end

httptunnel.cgi with lang statements and an entry for each language:

#!/bin/sh

. /usr/lib/libmodcgi.sh

check "$HTTPTUNNEL_ENABLED" yes:auto "*":man

sec_begin '$(lang de:"Starttyp" en:"Start type")'

cat << EOF
<p>
<input id="e1" type="radio" name="enabled" value="yes"$auto_chk><label for="e1">$(lang de:"Automatisch" en:"Automatic")</label>
<input id="e2" type="radio" name="enabled" value="no"$man_chk><label for="e2">$(lang de:"Manuell" en:"Manual")</label>
EOF
cat << EOF
</p>
EOF

sec_end
sec_begin '$(lang de:"httptunnel" en:"httptunnel")'

cat << EOF
<table border="0">
<tr>
        <td>$(lang de:"Destination Host" en:"Destination Host"):</td>
        <td><input type="text" name="host" size="80" maxlength="255" value="$(html "$HTTPTUNNEL_HOST")"></td>
</tr>
<tr>
        <td>$(lang de:"Destination Port" en:"Destination Port"):</td>
        <td><input type="text" name="hostport" size="5" maxlength="5" value="$(html "$HTTPTUNNEL_HOSTPORT")"></td>
</tr>
<tr>
        <td>$(lang de:"Client Port" en:"Client Port"):</td>
        <td><input type="text" name="clientport" size="5" maxlength="5" value="$(html "$HTTPTUNNEL_CLIENTPORT")"></td>
</tr>
<tr>
        <td>$(lang de:"Keep Alive" en:"Keep Alive"):</td>
        <td><input type="text" name="keepalive" size="3" maxlength="3" value="$(html "$HTTPTUNNEL_KEEPALIVE")"></td>
</tr>
<tr>
        <td>$(lang de:"Max Connection Age" en:"Max Connection Age"):</td>
        <td><input type="text" name="maxconnectionage" size="4" maxlength="4" value="$(html "$HTTPTUNNEL_MAXCONNECTIONAGE")"></td>
</tr>
<tr>
        <td>$(lang de:"Device" en:"Device"):</td>
        <td><input type="text" name="device" size="10" maxlength="10" value="$(html "$HTTPTUNNEL_DEVICE")"></td>
</tr>
</table>
EOF

sec_end

rc.httptunnel

Now we only need to write the rc.<package> file.
For this package the package name httptunnel and the binary hts differ. This requires the use of variable DAEMON for the package name, and DAEMON_BIN for the binary.
From the usage information we get that the binary gives an option to specify the PID-file. We will use this option in the rc.httptunnel file.
The binary is executed with the modlib_startdaemon function, which is using in the start () function. As parameter the DAEMON_BIN with its parameters is used.
For this package we have one conditional parameter. The DEVICE option should only be added to the list of parameters is it contains a non-zero amount of characters.
This is accomplished using a if [ test ] then function.
The case function test for a match. See the rc.<package> page for more information.

#!/bin/sh

DAEMON=httptunnel
DAEMON_BIN=hts
PID_FILE=/var/run/$DAEMON_BIN.pid
. /etc/init.d/modlibrc

start() {
        OPTIONS="-F $HTTPTUNNEL_HOST:$HTTPTUNNEL_HOSTPORT \
                -k $HTTPTUNNEL_KEEPALIVE \
                -M $HTTPTUNNEL_MAXCONNECTIONAGE \
                -p $PID_FILE \
                $HTTPTUNNEL_CLIENTPORT"
        [ -n "$HTTPTUNNEL_DEVICE" ] && OPTIONS="$OPTIONS -d $HTTPTUNNEL_DEVICE"
        modlib_startdaemon $DAEMON_BIN $OPTIONS
}

case $1 in
        ""|load)
                modreg cgi 'httptunnel' 'httptunnel'
                modreg daemon httptunnel

                modlib_start $HTTPTUNNEL_ENABLED
                ;;
        unload)
                modunreg daemon httptunnel
                modunreg cgi 'httptunnel'
                modlib_stop
                ;;
        start)
                modlib_start
                ;;
        stop)
                modlib_stop
                ;;
        restart)
                modlib_restart
                ;;
        status)
                modlib_status
                ;;
        *)
                echo "Usage: $0 [load|unload|start|stop|restart|status]" 1>&2
                exit 1
                ;;
esac

exit 0

Test on router

The following scripts can help to test the created files directly on the router.
For this the files are located on a USB-stick.
If the web-interface is working you can add the parameter 2 to obtain the config parameter values from tffs.

For the initial development of all files:

#!/bin/sh
export package=httptunnel
echo Will add webinterface for $package
[ ! -e /mod/etc/default.$package ] && mkdir /mod/etc/default.$package
[ ! -e /mod/etc/default.$package/$package.cfg ] && cp $package.cfg /mod/etc/default.$package/
if [ $1 -eq 2 ]; then
 modconf load $package
else
 [ ! -e /mod/etc/conf/$package.cfg ] && cp $package.cfg /mod/etc/conf/
fi
cd /var/mod/usr/lib/cgi-bin/
[ ! -e /var/mod/usr/lib/cgi-bin/$package.cgi ] &&  ln -s /var/media/ftp/uStor01/freetz/webinterface/$package/$package.cgi $package.cgi
cd /mod/etc/init.d/
[ ! -e /mod/etc/init.d/rc.$package ] && ln -s /var/media/ftp/uStor01/freetz/webinterface/$package/rc.$package rc.$package
rm /var/mod/var/cache/menu/packages
modreg cgi $package $package

For verifying changes to just the rc.<package> file e.g. after already including the files in the Freetz image:

#!/bin/sh
export package=httptunnel
cd /mod/etc/init.d/
[ -h /mod/etc/init.d/rc.$package ] && rm /mod/etc/init.d/rc.$package
[ ! -e /mod/etc/init.d/rc.$package ] && ln -s /var/media/ftp/uStor01/freetz/webinterface/$package/rc.$package rc.$package

References

To help with Bash Shell scripts: