Allocated a part of rules for user free configuration and a part
Marta Carbone [Mon, 16 Nov 2009 22:34:32 +0000 (22:34 +0000)]
for server|client|service configuration.
Added test and quiet options.

exec/ipfw-be

index 9cf2864..accda0b 100755 (executable)
@@ -13,9 +13,7 @@
 #
 # Configurable variables are at the beginning
 
-DEBUG=0 # set to 0 to disable debug messages
-
-# if HOOK is set the program is called befor configuring a rule.
+# 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=""
@@ -55,98 +53,130 @@ DEBUG=0 # set to 0 to disable debug messages
 #              pipe_out out src-port P
 #
 # The database of current ipfw and dummynet configuration is in a
-# file which is regenerated on error.
-# The format is
+# file which is regenerated on errors. The format is
 #
-#      slice_id service_type port rule_nr pipe_base timeout
+#      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
-LOG_FILE=/tmp/netconfig.log # XXX when running from daemon
 lockfile=/var/lock/ipfw.lock
-PIPE_MIN=1000
-PIPE_MAX=30000
+
+# 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
-# XXX check consintency variable {}
+# XXX check consistency for variables {}
 SED=/bin/sed
-#IPFW="/bin/echo ipfw:"
+SEDOPT=-r
+[ -x ${SED} ] || { SED=`which sed` ; SEDOPT=-E ; }
 IPFW=/sbin/ipfw
-
-# Call arguments are <backend-program> <caller_slice_name>
-SLICENAME="$1" # save the slice XXX name or id ?
-SLICE_ID=`id -u $SLICENAME`
+IPFW_CHECK="/sbin/ipfw -n"
 
 debug() { # $1 message to be displayed
-       #echo "ipfw-be: $1"
-       [ x"${DEBUG}" != x"0" ] && echo "ipfw-be: $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
        release_lock
        echo "ipfw-be aborting: $1"
        exit 1
 }
 
-user_error() { # $1 message to be displayed
-       echo "ipfw-be: 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
-       # allowed chars are: numbers, upcase and lowecase
-       # chars, and the following symbols: . _ - /
-       echo "$*" | ${SED} -r 's/[^0-9a-zA-Z. _\/\-{}]*//g'
+       [ 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'
+}
+
+# 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 port rule pipe_base timeout
-    local new_rule=$1 slice_id=$2 type=$3 port=$4 rule_nr=$5 pipe_base=$6 timeout=$7
+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
 
-    # XXX validate the timeout
-    # schedule the rule deletion
-    check_timeout=`date --date="${timeout}" +%s`
-    [ x"${check_timeout}" = x"" ] && abort "Date format $1 not valid"
-    # XXX tbd
-    timeout="fake_timeout"
-
-    # we could use a profile, so locate the user directory
+    # If we use a profile file, locate the user directory
     # move in the slice root dir XXX todo
-    cd /vservers/${SLICENAME}/root
+    [ "$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
-    # check syntax, if ok move on and do the action
-    local IPFW_CHECK="${IPFW} -n "
-
-    pipe_in=$(($pipe_base + $pipe_base))
+    # 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  # which one to delete ?
+    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 $port"
-           rule_out="src-port $port"
-           del=SERVICE
+       server)
+           rule_in="dst-port $arg"
+           rule_out="src-port $arg"
+           del=service
            ;;
-       CLIENT)
-           rule_in="src-port $port"
-           rule_out="dst-port $port"
-           del=SERVICE
+       client)
+           rule_in="src-port $arg"
+           rule_out="dst-port $arg"
+           del=service
            ;;
-       SERVICE)
-           rule_in="{ src-port $port or dst-port $port }"
-           rule_out="{ src-port $port or dst-port $port }"
-           del="CLI_SER"
+       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"
@@ -155,64 +185,71 @@ add_rule() { # new_rule slice_id type port rule pipe_base timeout
 
        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 || \
-               user_error "ipfw syntax error $rule_in"
-       ${IPFW_CHECK} add ${rule_nr} $rule_out || \
-               user_error "ipfw syntax error $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
 
-    # XXX check error reporting
-    ${IPFW_CHECK} pipe ${pipe_in} config ${CONFIG_PIPE_IN} || \
-               user_error "ipfw syntax error pipe_in"
-    ${IPFW_CHECK} pipe ${pipe_out} config ${CONFIG_PIPE_OUT} || \
-               user_error "ipfw syntax error pipe_out"
+    # 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" ] && delete_config $slice_id SERVICE $port
-    [ "$del" = "CLI_SER" ] && delete_config $slice_id CLIENT $port
-    [ "$del" = "CLI_SER" ] && delete_config $slice_id SERVER $port
-    [ "$new_rule" != "0" ] && ${IPFW} add ${rule_nr} $rule_in
-    [ "$new_rule" != "0" ] && ${IPFW} add ${rule_nr} $rule_out
+    [ "$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} ${port}" $DBFILE;  \
-       echo "${slice_id} ${type} ${port} ${rule_nr} ${pipe_base} ${timeout}" ) > ${DBFILE}.tmp
+    ( 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
-delete_config() { # slice_id type port
-    local pipe_in pipe_out pipe_base
-    local slice_id=$1 type=$2 port=$3
+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
 
-    # XXX test
-    [ $# -lt 3 ] && abort "One or more input parameter is missing"
-    set `find_rule $slice_id $type $port`
-    rule=$1; pipe_base=$2
-    [ "$rule" = "0" ] && return                # no rules found
+    [ "${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
 
-    pipe_in=$(($pipe_base + $pipe_base))
+    rule_nr=$(($rule_base + 39999))            # XXX only individual rules
+    pipe_in=$(($pipe_base + $pipe_base + 9998))
     pipe_out=$(($pipe_in + 1))
 
-    $IPFW delete ${rule}
+    $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} ${port}" $DBFILE > ${DBFILE}.tmp
+    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 loc_port rem_port> with
+# compare the tuple <slice_id type arg> with
 # the current firewall configuration. The database contains
-#      slice_id local_port remote_port rule_nr pipe_nr timeout
-# On match returns <rule_nr pipe_base timeout>
+#      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 port
+find_rule() { # $1 slice_id $2 type $3 arg
     local ret
     ret=`grep -- "^$1 $2 $3 " $DBFILE`
 
@@ -238,133 +275,181 @@ find_hole() {  # min max
     echo $cand
 }
 
-# returns a free rule and pipe base 
+# returns a free rule and pipe base for client|server|service
 # Returns r=0 if there are no resources available
-#
-# This function returns values using echo,
-# this means that we can not easily debug the function
 allocate_resources() {
     local p r
     # remove comments, extract field, sort
-    p=`grep -v '^#' $DBFILE | awk '{print $5}' | sort -n | find_hole 1 10000`
-    r=`grep -v '^#' $DBFILE | awk '{print $4}' | sort -n | find_hole $PIPE_MIN $PIPE_MAX`
+    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 ${type} ${port} ${timeout} PIPE_IN <pipe in parameters> PIPE_OUT <pipe out parameters>
-# IPFW_SHOW
-# PIPE_SHOW
-# DELETE ${type} ${port}
+# 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() { 
+process() {
     local new_pipe=0
-    local timeout TMP i rule_nr pipe_base
-    local type=$2
-    local port=$3
-
-    debug "Received from the input pipe: $*"
+    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"$1" in 
-    x"IPFW_SHOW") 
-       ${IPFW} show
-       return 0
+    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"PIPE_SHOW")
-       $IPFW pipe show
-       return 0
+    x"delete") 
+       do_delete ${SLICE_ID} $type $args
        ;;
-    x"DELETE")
-       delete_config ${SLICE_ID} $type $port
-       return 0
+    x"refresh") 
+       abort "XXX unimplemented " && return 0
+       do_refresh ${SLICE_ID} $type $args $timeout
        ;;
-    x"CONFIG")
+    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}"
        ;;
     *)
-       abort "Command not recognized"
+       # help XXX to be done
+       abort "'command' should be one of {show|config|delete|refresh|release}"
        ;;
     esac
-    shift
+}
 
-    debug "processed initial command, rest of line: $*"
-    # check if we have enough parameters
-    [ $# -lt 9 ] && abort "One or more input parameter is missing"
+# validate the timeout
+check_timeout() { # timeout
+    local tt=`date --date="${1}" +%s`
+    [ "$?" != "0" ] && abort "Date format $1 not valid"
+}
 
-    type=$1; shift
-    port=$1; shift
-    timeout=$1; shift
-    # XXX check/compute timeout
+do_release() { # slice_id type args timeout
+    return
+}
+
+do_refresh() { # slice_id ttype args
+    return
+}
 
-    [ "$1" != "PIPE_IN" ] && abort "PIPE_IN requested"
+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"
+    CONFIG_PIPE_IN="$i"                # XXX local ?
+    [ "$CONFIG_PIPE_IN" = "" ] && abort "Missing pipe in configuration"
 
-    [ "$1" != "PIPE_OUT" ] && abort "PIPE_OUT requested"
+    [ "$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"
+    CONFIG_PIPE_OUT="$i"       # XXX local ?
+    [ "$CONFIG_PIPE_OUT" = "" ] && abort "Missing pipe out configuration"
 
     debug "Configuration Required:"
-    debug "TYPE: $type"
-    debug "PORT: $port"
-    debug "TIMEOUT: $timeout"
-    debug "pipe in config $CONFIG_PIPE_IN"
-    debug "pipe in config $CONFIG_PIPE_OUT"
+    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} ${port}"
+    debug "Search for ${slice_id} ${type} ${arg}"
 
-    set `find_rule ${SLICE_ID} ${type} ${port}`
-    rule_nr=$1
-    pipe_base=$2
+    set `find_rule ${slice_id} ${type} ${arg}`
+    local rule_base=$1
+    local pipe_base=$2
+    local new_pipe=0
 
-    if [ ${rule_nr} = "0" ] ; then
+    if [ ${rule_base} = "0" ] ; then
        debug "Rule not found, new installation"
        new_pipe=1
-       set `allocate_resources`
-       rule_nr=$1; pipe_base=$2
-        [ $rule_nr = 0 ] && abort "no resources available"
-       debug "found free resources rule: $rule_nr pipe: $pipe_base"
+       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 $port $rule_nr $pipe_base $timeout
+
+    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_nr $pipe_base $timeout &
+       ${HOOK} $slice_id $type $port $rule_base $pipe_base $timeout &
     fi
 }
 
 #
 # acquire the lock XXX check lockfile
-acquire_lock()
-{
+acquire_lock() {
+    [ "$TEST" = 1 ] && return
     lockfile -s 0 -r 0 $lockfile 2> /dev/null
     if [ $? -ne 0 ] ; then
        echo "lock acquisition failed"
@@ -374,47 +459,43 @@ acquire_lock()
 
 #
 # release the lock
-release_lock()
-{
+release_lock() {
     rm -f $lockfile
 }
 
-# main starts here
-       debug "Debug activated"
-       debug "$0 START"
-
-       # create the DBFILE if not exist
-       [ ! -e ${DBFILE} ] && touch ${DBFILE}
-
-       requests=[]
-       i=0
-
-       # lock acquisition
-       acquire_lock    
-
-       # A request to the vsys backend is composed by a single line of input
-       while read request; do
-               # read -a read arguments in array
-               # XXX skip lines starting with #
-               debug "Received <$request>"
-               requests[$i]="$request"
-               requests[$i]=`filter $request`
-               debug "Filtered ${requests[$i]}"
-               i=$(($i + 1))
-       done
-
-       # process requests
-       i=0
-       n_req=${#requests[*]}
-       debug "Received $n_req request"
-       while [ $i -lt $n_req ] ; do
-               debug "processing request $i of $n_req"
-               debug "<${requests[$i]}>"
-               process ${requests[$i]}
-               i=$(($i + 1))
-       done
-
-       # lock release
-       release_lock
-       debug "$0 END"
-       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