#!/bin/sh
#
-# Marta Carbone
-# Copyright (C) 2009 UniPi
+# Marta Carbone, Luigi Rizzo
+# Copyright (C) 2009 Universita` di Pisa
# $Id$
#
-# This script is the backend to be used with
-# the vsys system.
-# It allows to configure dummynet pipes and queues.
+# This script the vsys backend used to configure emulation.
# In detail it:
-# - read the user's input from the input pipe
-# - validate the input
-# - set the firewall
-# - put results on the output vsys pipe
+# - reads the user's input from the vsys input pipe
+# - validates the input
+# - configures the firewall
+# - writes results on the output vsys pipe
#
-# This script expect to read from the input vsys
-# pipe a line formatted as follow:
-# ${PORT} ${TIMEOUT} <dummynet parameters>
-# the timeout value is expressed as:
-# week, day, month or anything else accepted by the date command
+# Configurable variables are at the beginning
-# save the slicename
-SLICE=$1
+# If HOOK is set the program is called before configuring a rule.
+# A sample hook can be found in the ipfw.rpm package
+# HOOK=/tmp/sample_hook
+# XXX HOOK=""
-LOG_FILE=/tmp/netconfig.log
+# You should not touch anything below.
+
+# We assume three type of connections
+# SERVER we know the local port P, and do the
+# bind/listen/accept on the local socket.
+# pipe_in in dst-port P
+# pipe_out out src-port P
+#
+# CLIENT we know the remote port P, and do a connect to it
+# (src and dst are swapped wrt the previous case)
+# pipe_in in src-port P
+# pipe_out out dst-port P
+#
+# SERVICE we run a server on local port P, and also connect
+# from local clients to remote servers on port P.
+# pipe_in in { dst-port P or src-port P }
+# pipe_out out { src-port P or dst-port P }
+#
+# On a given port a user can have one CLIENT and/or one SERVER
+# configuration or one SERVICE configuration.
+# When a SERVICE configuration is installed any existing CLIENT
+# and SERVER configuration on the same port are removed.
+# When a CLIENT or SERVER configuration is installed any existing
+# SERVICE configuration on the same port is removed.
+#
+# The following is a case that is implemented as SERVER
+# D we run a server on local port P, and also connect
+# to remote servers but doing a bind(P) before connect().
+# In terms of rules, this is not distinguishable from
+# the SERVER case, however it would be different if we
+# had a way to tell SERVER from CLIENT sockets
+# pipe_in in dst-port P
+# pipe_out out src-port P
+#
+# The database of current ipfw and dummynet configuration is in a
+# file which is regenerated on errors. The format is
+#
+# slice_id type arg rule_base pipe_base timeout
+#
+# (lines starting with '#' are comments and are ignored)
+# For each configuration we allocate one rule number in ipfw,
+# and two sequential pipe numbers.
+
+# globals, do not touch below
+VERBOSE=0 # set to !0 to enable debug messages
+TEST=0 # set to 1 for test mode
+
+DBFILE=/tmp/ff
+lockfile=/var/lock/ipfw.lock
+
+# There values are the keys used in the database for rules and pipes
+# rule_nr 1..10000 are mapped to rules 10000..49999 (n*4+9996)
+# rule_nr 10001..20000 are mapped to rules 50000..59999 (n+39999)
+# pipe_nr 1..25000 are mapped to pipes 10000-59999 (n*2+9998)
+RULE_BL_MIN=1
+RULE_BL_MAX=10000
+RULE_IN_MIN=10001
+RULE_IN_MAX=20000
+PIPE_MIN=1
+PIPE_MAX=25000
+# These are the rule numbers used in ipfw
+IPFW_RULE_MIN=10000
+IPFW_RULE_MAX=59999
+IPFW_PIPE_MIN=10000
+IPFW_PIPE_MAX=59999
+
+# set slicename and slice_id
+# there represents the credential of the user
+SLICENAME=$1
+SLICE_ID=`id -u $SLICENAME`
+[ $? != 0 ] && abort "Invalid slicename $SLICENAME"
# programs
-CUT=/usr/bin/cut
+# XXX check consistency for variables {}
SED=/bin/sed
+SEDOPT=-r
+[ -x ${SED} ] || { SED=`which sed` ; SEDOPT=-E ; }
IPFW=/sbin/ipfw
-
-# set to 0 to disable debug messages
-DEBUG=0
+IPFW_CHECK="/sbin/ipfw -n"
debug() { # $1 message to be displayed
- [ x"${DEBUG}" != x"0" ] && echo $1 >>{LOG_FILE};
+ [ x"${VERBOSE}" != x"0" ] && echo "ipfw-be: $1"
+}
+# if the first argument is -v, enable verbose mode
+set_verbose() {
+ [ x"$1" = x"-v" -o x"$2" = x"-v" ] && VERBOSE=1
+ echo "in set_verbose have $VERBOSE $1"
}
+set_test() {
+ [ x"$1" = x"-q" -o x"$2" = x"-q" ] || return
+ TEST=1
+ IPFW="/bin/echo ipfw:"
+ IPFW_CHECK="/bin/echo ipfw -n:"
+}
+
abort() { # $1 message to be displayed
- echo "$1"
+ release_lock
+ echo "ipfw-be aborting: $1"
exit 1
}
-user_error() { # $1 message to be displayed
- echo "1 User error: $1"
- exit 1
+# remove dangerous characters from user input
+# if present, the leading '-v/-t' will be removed
+filter() { # $* variables to be filtered
+ [ x${1} = x"-v" -o x${1} = x"-q" ] && shift
+ [ x${1} = x"-v" -o x${1} = x"-q" ] && shift
+ # allowed chars are: numbers, uppercase and lowercase letters,
+ # spaces, and the following symbols: .,_-/
+ echo "$*" | ${SED} ${SEDOPT} 's/[^\t0-9a-zA-Z., _\/\{}-]*//g'
}
-filter() { # $* variables to be filtered
- # allowed chars are: numbers, upcase and lowecase
- # chars, and the following symbols: . _ - /
- echo "$*" | ${SED} -r 's/[^0-9a-zA-Z. _\/\-]*//g'
-}
-
-# Add ipfw pipe and rules
-# We use the PORT number to configure the
-# pipe, and add rules for that port.
-# The default directory is the slicename root
-add_rules() { # $1 timeout value
- local EXPIRE
-
- debug "Add a new rule"
- # schedule the rule deletion
- EXPIRE=`date --date="${TIMEOUT}" +%s`
- [ x"${EXPIRE}" = x"" ] && abort "Date format $1 not valid"
-
- # move in the slice root dir
- cd /vservers/${SLICE}/root
- #echo ${CONFIG_STRING} | ${SED} -e "s/ profile \(.[^ ]\)/ profile \/vservers\/${SLICE}\/\1/g"
-
- # check syntax, if ok execute
- # add rules
- local IPFW_CHECK="${IPFW} -n "
- local ERROR=0
-
- [ $ERROR -eq 0 ] && \
- ${IPFW_CHECK} add ${RULE_N} pipe ${PIPE_N} ip from me to any src-port ${PORT} // ${EXPIRE} ${SLICE}
- let "ERROR += $?"
- [ $ERROR -eq 0 ] && \
- ${IPFW_CHECK} add ${RULE_N} pipe ${PIPE_N} ip from any to me dst-port ${PORT}
-
- let "ERROR += $?"
- [ $ERROR -eq 0 ] && \
- ${IPFW_CHECK} pipe ${PIPE_N} config ${PARSED_CONFIGURATION}
-
- if [ ! $ERROR -eq 0 ]; then
- echo "Some errors occurred not executing"
- user_error "ipfw syntax error"
- fi
-
- # add rules
- ${IPFW} add ${RULE_N} pipe ${PIPE_N} ip from me to any src-port ${PORT} // ${EXPIRE} ${SLICE}
- ${IPFW} add ${RULE_N} pipe ${PIPE_N} ip from any to me dst-port ${PORT}
-
- # config pipe
- ${IPFW} pipe ${PIPE_N} config ${PARSED_CONFIGURATION}
-}
-
-# Delete a given link
-delete_link()
-{
- ipfw delete ${RULE_N}
- ipfw pipe delete ${RULE_N}
-}
-
-# The rule we want to configure already exist.
-# Check for slice owner matching.
-modify_rule()
-{
- local RULE
-
- RULE=`ipfw list ${PORT} 2>&1 | cut -d ' ' -f 12`;
- if [ "${RULE}" = "${SLICE}" ] ; then # replace the link configuration
- debug "The rule already exist, the owner match, delete old rule"
- echo "Owner match"
- delete_link
- add_rules ${TIMEOUT}
- else
- user_error "the rule already exist, ant you are not the slice owner, try later"
- fi
-}
-
-# process a single line of input, a request
-process()
-{
- local TMP; # temporary var
-
- debug "Received from the input pipe: $1"
-
- # allow netconfig ipfw show
- # allow netconfig pipe show
-
- CMD=`echo $1 | cut -d\ -f 1`
- if [ x${CMD} == x"ipfw" ]; then
- ipfw show
- return 0
- else if [ x${CMD} == x"pipe" ]; then
- ipfw pipe show
- return 0
- fi
- fi
-
- ARGS=`echo $1 | wc -w`
- if [ $ARGS -le 3 ]; then
- abort "One or more input parameter is missing"
- fi
-
- # filter input
- TMP=`echo $1 | cut -d\ -f 1`
- PORT=`filter $TMP`
- TMP=`echo $1 | cut -d\ -f 2`
- TIMEOUT=`filter $TMP`
- TMP=`echo $1 | cut -d\ -f 3-`
- CONFIG_STRING=`filter $TMP`
-
- debug "PORT: $PORT"
- debug "TIMEOUT: $TIMEOUT"
- debug "configuration string: $CONFIG_STRING"
-
- # deny port <= 1024
- [ ${PORT} -le 1024 ] && user_error "it is not allowed to modify the port range [0-1024]"
-
- # start to configure pipes and rules
- PIPE_N=${PORT}
- RULE_N=${PORT}
-
- # check if the link is already configured
- ipfw list ${PORT} 2>&1
-
- if [ x"$?" != x"0" ]; then # new rule, add and set owner/timeout
- add_rules
- else # the rule already exist, check owner
- modify_rule
- fi
-
-}
-
-# main starts here
-
- requests=[]
- i=0
-
- while read request
- do
- # read -a read arguments in array
- # XXX skip lines starting with #
- requests[$i]=$request;
- let i=$i+1
- done
+# remove all entries from the ipfw config, and create an empty db
+clean_db() {
+ rm -f ${DBFILE}
+ touch ${DBFILE}
+ # we would like to delete ranges of rules and pipes but this
+ # is not supported so for the time being we kill them all
+ ${IPFW} -q flush
+ ${IPFW} -q pipe flush
+ # ${IPFW} delete ${IPFW_RULE_MIN}-${IPFW_RULE_MAX}
+ # ${IPFW} pipe delete ${IPFW_PIPE_MIN}-${IPFW_PIPE_MAX}
+}
+
+# Add the ipfw rule/pipe and update the database.
+# The pipe-in and pipe_out config are through global variables
+# CONFIG_IN CONFIG_OUT because they may be long.
+# Other arguments are on the command line
+add_rule() { # new_rule slice_id type arg rule pipe_base timeout
+ local new_rule=$1 slice_id=$2 type=$3 arg=$4
+ local rule_base=$5 pipe_base=$6 timeout=$7
+ local pipe_in pipe_out rule_in rule_out check_timeout
+
+ # If we use a profile file, locate the user directory
+ # move in the slice root dir XXX todo
+ [ "$TEST" != "1" ] && cd /vservers/${SLICENAME}/root
+ #echo ${CONFIG_STRING} | ${SED} -e "s/ profile \(.[^ ]\)/ profile \/vservers\/${SLICENAME}\/\1/g"
+
+ # first, call ipfw -n to check syntax, if ok move on and do the action
+ pipe_in=$(($pipe_base + $pipe_base + 9998))
+ pipe_out=$(($pipe_in + 1))
+ local del # anything to delete ?
+ local rule_nr=$(($rule_base + 39999)) # XXX formula for individual rules
+ if [ x"$new_rule" != x"0" ] ; then
+ case $type in
+ server)
+ rule_in="dst-port $arg"
+ rule_out="src-port $arg"
+ del=service
+ ;;
+ client)
+ rule_in="src-port $arg"
+ rule_out="dst-port $arg"
+ del=service
+ ;;
+ service)
+ rule_in="{ src-port $arg or dst-port $arg }"
+ rule_out="{ src-port $arg or dst-port $arg }"
+ del="cli_ser"
+ ;;
+ *)
+ abort "invalid service type $type"
+ ;;
+ esac
+
+ rule_in="pipe ${pipe_in} in uid $slice_id ${rule_in}"
+ rule_out="pipe ${pipe_out} out uid $slice_id ${rule_out}"
+ ${IPFW_CHECK} add ${rule_nr} $rule_in > /dev/null || \
+ abort "ipfw syntax error $rule_in"
+ ${IPFW_CHECK} add ${rule_nr} $rule_out > /dev/null || \
+ abort "ipfw syntax error $rule_out"
+ fi
+
+ # check error reporting
+ ${IPFW_CHECK} pipe ${pipe_in} config ${CONFIG_PIPE_IN} > /dev/null || \
+ abort "ipfw syntax error pipe_in"
+ ${IPFW_CHECK} pipe ${pipe_out} config ${CONFIG_PIPE_OUT} > /dev/null || \
+ abort "ipfw syntax error pipe_out"
+
+ # all good, delete and add rules if necessary
+ [ "$del" = "service" ] && do_delete $slice_id service $arg
+ [ "$del" = "cli_ser" ] && do_delete $slice_id client $arg
+ [ "$del" = "cli_ser" ] && do_delete $slice_id server $arg
+ [ "$new_rule" != "0" ] && ${IPFW} add ${rule_nr} $rule_in > /dev/null
+ [ "$new_rule" != "0" ] && ${IPFW} add ${rule_nr} $rule_out > /dev/null
+ # config pipes
+ ${IPFW} pipe ${pipe_in} config ${CONFIG_PIPE_IN}
+ ${IPFW} pipe ${pipe_out} config ${CONFIG_PIPE_OUT}
+
+ # send output to the user
+ ${IPFW} show ${rule_nr}
+ ${IPFW} pipe ${pipe_in} show
+ ${IPFW} pipe ${pipe_out} show
+
+ [ "$TEST" = "1" ] && return
+ # add to the database, at least to adjust the timeout
+ ( grep -v -- "^${slice_id} ${type} ${arg}" $DBFILE; \
+ echo "${slice_id} ${type} ${arg} ${rule_base} ${pipe_base} ${timeout}" ) > ${DBFILE}.tmp
+ mv ${DBFILE}.tmp ${DBFILE}
+}
+
+# Delete a given configuration
+do_delete() { # slice_id type arg
+ local pipe_in pipe_out pipe_base rule_base rule_nr
+ local slice_id=$1 type=$2 arg=$3
+
+ [ "${arg}" = "" ] && abort "Missing arg on 'delete'"
+ set `find_rule $slice_id $type $arg`
+ rule_base=$1; pipe_base=$2
+ [ "$rule_base" = "0" ] && return # no rules found
+
+ rule_nr=$(($rule_base + 39999)) # XXX only individual rules
+ pipe_in=$(($pipe_base + $pipe_base + 9998))
+ pipe_out=$(($pipe_in + 1))
+
+ $IPFW delete ${rule_nr}
+ $IPFW pipe delete ${pipe_in}
+ $IPFW pipe delete ${pipe_out}
+ echo "removed configuration $slice_id} ${type} ${arg}"
+ [ "$TEST" = "1" ] && return
+ # remove from the database
+ grep -v -- "^${slice_id} ${type} ${arg}" $DBFILE > ${DBFILE}.tmp
+ mv ${DBFILE}.tmp ${DBFILE}
+}
+
+# called with the database file as input
+# compare the tuple <slice_id type arg> with
+# the current firewall configuration. The database contains
+# slice_id type arg rule_base pipe_base timeout
+# On match returns <rule_base pipe_base timeout>
+# On non match returns 0 0 0
+find_rule() { # $1 slice_id $2 type $3 arg
+ local ret
+ ret=`grep -- "^$1 $2 $3 " $DBFILE`
+
+ [ x"$ret" = x ] && echo "0 0 0 " && return # nothing found
+ # ignore multiple matches. If the db is corrupt we are
+ # screwed anyways
+ set $ret
+ echo "$4 $5 $6"
+}
+
+
+# Find a hole in a list of numbers within a range (boundaries included)
+# The input is passed as a sorted list of numbers on stdin.
+# Return a "0" rule if there is no rule free
+find_hole() { # min max
+ local min=$1 cand=$1 max=$2 line
+ while read line ; do
+ [ $line -lt $min ] && continue
+ [ $line -ne $cand ] && break # found
+ [ $cand -ge $max ] && cand=0 && break # no space
+ cand=$(($cand + 1))
+ done
+ echo $cand
+}
+
+# returns a free rule and pipe base for client|server|service
+# Returns r=0 if there are no resources available
+allocate_resources() {
+ local p r
+ # remove comments, extract field, sort
+ p=`grep -v '^#' $DBFILE | awk '{print $5}' | sort -n | \
+ find_hole $PIPE_MIN $PIPE_MAX`
+ r=`grep -v '^#' $DBFILE | awk '{print $4}' | sort -n | find_hole $1 $2`
+ [ $r = 0 -o $p = 0 ] && r=0 # no resources available
+ echo $r $p
+}
+
+# process a request.
+# A request is made by a set of arguments formatted as follow:
+#
+# config {server|client|service} arg [-t timeout] PIPE_IN <pipe_conf> PIPE_OUT <pipe_conf>
+# show {rules|pipes} [args]
+# delete type arg
+#
+# XXX not implemented yet
+# config {rule|pipe} num <parameters>
+# alloc rules|pipes [-t timeout] # returns a block of NUM_RULES or NUM_PIPES
+# release rules|pipes args # release the entire block
+# refresh rules|pipes args [-t timeout]
+#
+# where uppercase values are keywords.
+# The timeout value is expressed as:
+# week, day, month or anything else accepted by the date command.
+# The id of the slice issuing the request is in the $SLICE_ID variable,
+# set at the beginning of this script.
+process() {
+ local new_pipe=0
+ local timeout TMP i rule_base pipe_base
+ local slicename=${SLICENAME}
+ local cmd=$1 ; shift
+ local debug_args="$*";
+ local type=$1 ; shift
+ local args="$*"
+ debug "Received command: <$cmd> arguments: <$debug_args>"
+
+ # set the timeout value
+ # clean args from the timeout keyword
+ timeout=`echo ${args} | ${SED} ${SEDOPT} 's/(.+)( -t [a-zA-Z0-9]+ )(.*)/\2/'`
+ if [ "${timeout}" != "${args}" ] ; then # match
+ timeout=`echo ${timeout} | ${SED} ${SEDOPT} 's/-t //'`
+ check_timeout ${timeout} # abort on error
+ args=`echo ${args} | ${SED} ${SEDOPT} 's/(.+)( -t [a-zA-Z0-9]+ )(.*)/\1 \3/'`
+ else
+ timeout=1day # default to 1 day
+ fi
+
+ debug "Timeout $timeout"
+ # Handle special requests: show and delete
+ case x"$cmd" in
+ x"alloc")
+ abort "XXX unimplemented " && return 0
+ ;;
+ x"config")
+ [ "$type" = "server" ] && do_config $SLICE_ID $timeout $type $args && return 0
+ [ "$type" = "client" ] && do_config $SLICE_ID $timeout $type $args && return 0
+ [ "$type" = "service" ] && do_config $SLICE_ID $timeout $type $args && return 0
+ [ "$type" = "rule" ] && abort "XXX unimplemented " && return 0
+ [ "$type" = "pipe" ] && abort "XXX unimplemented " && return 0
+ abort "'config' should be followed by {server|client|service|rule|pipe}"
+ ;;
+ x"delete")
+ do_delete ${SLICE_ID} $type $args
+ ;;
+ x"refresh")
+ abort "XXX unimplemented " && return 0
+ do_refresh ${SLICE_ID} $type $args $timeout
+ ;;
+ x"release")
+ abort "XXX unimplemented " && return 0
+ do_release ${SLICE_ID} $type $args
+ ;;
+ x"show")
+ # XXX should filter on uid
+ [ "$type" = "rules" ] && ${IPFW} show && return 0
+ [ "$type" = "pipes" ] && ${IPFW} pipe show && return 0
+ abort "'show' should be followed by {rules|pipes}"
+ ;;
+ *)
+ # help XXX to be done
+ abort "'command' should be one of {show|config|delete|refresh|release}"
+ ;;
+ esac
+}
+
+# validate the timeout
+check_timeout() { # timeout
+ local tt=`date --date="${1}" +%s`
+ [ "$?" != "0" ] && abort "Date format $1 not valid"
+}
+
+do_release() { # slice_id type args timeout
+ return
+}
+
+do_refresh() { # slice_id ttype args
+ return
+}
+
+do_config() { # slice_id timeout type arg PIPE_IN pipe_conf PIPE_OUT pipe_conf
+ local slice_id=$1; shift
+ local timeout=$1; shift
+ local type=$1; shift
+ local arg=$1; shift # XXX addr not yet implemented
+
+ [ "$1" != "PIPE_IN" ] && abort "Missing addr:port, or PIPE_IN requested"
+ shift
+
+ # read pipe in configuration
+ i=""
+ while [ "$1" != "" -a "$1" != "PIPE_OUT" ] ; do
+ i="$i $1"
+ shift
+ done
+ CONFIG_PIPE_IN="$i" # XXX local ?
+ [ "$CONFIG_PIPE_IN" = "" ] && abort "Missing pipe in configuration"
+
+ [ "$1" != "PIPE_OUT" ] && abort "Missing pipe in configuration, or missing PIPE_OUT"
+ shift
+
+ # read pipe out configuration
+ i=""
+ while [ "$1" != "" ] ; do
+ i="$i $1"
+ shift
+ done
+ CONFIG_PIPE_OUT="$i" # XXX local ?
+ [ "$CONFIG_PIPE_OUT" = "" ] && abort "Missing pipe out configuration"
+
+ debug "Configuration Required:"
+ debug "slice_id: $slice_id"
+ debug "type: $type"
+ debug "arg: $arg"
+ debug "timeout: $timeout"
+ debug "PIPE_IN: $CONFIG_PIPE_IN"
+ debug "PIPE_OUT: $CONFIG_PIPE_OUT"
+ debug "-----------------------"
+
+ # check if the link is already configured
+ debug "Search for ${slice_id} ${type} ${arg}"
+
+ set `find_rule ${slice_id} ${type} ${arg}`
+ local rule_base=$1
+ local pipe_base=$2
+ local new_pipe=0
+
+ if [ ${rule_base} = "0" ] ; then
+ debug "Rule not found, new installation"
+ new_pipe=1
+ set `allocate_resources $RULE_IN_MIN $RULE_IN_MAX`
+ rule_base=$1; pipe_base=$2
+ [ $rule_base = 0 ] && abort "no resources available"
+ debug "found free resources rule: $rule_base pipe: $pipe_base"
+ else
+ debug "Rule found, just changing the pipe configuration"
+ fi
+
+ add_rule $new_pipe $slice_id $type $arg $rule_base $pipe_base $timeout
+
+ # if present, call a hook in order to collect statistical
+ # information on dummynet usage
+ if [ -n "${HOOK}" -a -x "${HOOK}" ]; then
+ # XXX
+ ${HOOK} $slice_id $type $port $rule_base $pipe_base $timeout &
+ fi
+}
+
+#
+# acquire the lock XXX check lockfile
+acquire_lock() {
+ [ "$TEST" = 1 ] && return
+ lockfile -s 0 -r 0 $lockfile 2> /dev/null
+ if [ $? -ne 0 ] ; then
+ echo "lock acquisition failed"
+ exit -1
+ fi
+}
+
+#
+# release the lock
+release_lock() {
+ rm -f $lockfile
+}
- # create the lock
-
- # process requests
- for i in `/usr/bin/seq 0 $((${#requests[*]} - 1))`
- do
- process "${requests[$i]}"
- done
-
- # delete the lock
- exit 0
+# ALLOCATION OF PIPES AND RULES
+# pipes are always allocated in pairs
+# rules are either individual or in groups of size NUM_RULES (e.g. 4)
+# and are allocated in two different parts of the rule namespace
+# (e.g. blocks from 10000 to 49999 and individuals from 50000 to 59999)
+# Internally allocator uses the base number for each item, e.g.
+# rule 10000..49999 -> rule_base=1..10000
+# rule 50000..59999 -> rule_base=10001..20000
+# pipe 10000..59999 -> pipe_base=1..25000
+# a bit of math lets us compute the correct numbers.
+# For CLIENT, SERVER, SERVICE the database contains entries as
+# XID TYPE arg rule_base pipe_base
+# For blocks the entries are
+# XID RULE - rule_base -
+# XID PIPE - - pipe_base
+# When a rule or pipe is referenced we first check that the owner owns it.
+# more details below.
+
+#-- main starts here
+debug "--- $0 START for $SLICENAME ---"
+
+# If the db does not exist, create it and we clean rules and pipes
+[ ! -e ${DBFILE} ] && clean_db
+
+# A request to the vsys backend is composed by a single line of input
+read REQ # read one line, ignore the rest
+echo "read ${REQ}"
+set_verbose ${REQ} # use inital -v if present
+set_test ${REQ} # use inital -t if present
+REQ="`filter ${REQ}`" # remove -v and -t and invalid chars
+debug "--- processing <${REQ}>"
+acquire_lock # critical section
+process ${REQ}
+release_lock
+debug "--- $0 END ---"
+exit 0