#!/bin/sh # # Marta Carbone, Luigi Rizzo # Copyright (C) 2009 Universita` di Pisa # $Id$ # # This script the vsys backend used to configure emulation. # In detail it: # - reads the user's input from the vsys input pipe # - validates the input # - configures the firewall # - writes results on the output vsys pipe # # Configurable variables are at the beginning # If HOOK is set the program is called before configuring a rule. # A sample hook can be found in the ipfwroot.rpm package, # it can be used to collect statistical information on dummynet usage. # To configure an hook, set the HOOK variable as follow: # HOOK=/tmp/sample_hook # 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 # These values are the keys used in the database for blocks # and pipes. For rules we store directly the ipfw number. # # For each user we allocate a block of $M rules. The rules # allocated to users are within the range: # ipfw_min_rule = RULE_BASE # ipfw_max_rule = RULE_BASE + ((M-1)*block_n) -1 BLOCK_MIN=1 BLOCK_MAX=1000 M=50 # block size PIPE_MIN=1 PIPE_MAX=25000 # These are the actual rule numbers used in ipfw IPFW_RULE_MIN=10000 IPFW_PIPE_MIN=10000 # The skipto and the generic default rule # these values are used to initialize the firewall SLICE_TABLE=1 # table number used for slice ids lookup S=1000 # firewall rule number for the skipto rule D=2000 # default rule for reserved section # set slicename and slice_id # these are the credential of the user invoking the backend SLICENAME=$1 SLICE_ID=`id -u $SLICENAME` [ x"$SLICE_ID" = x"" ] && echo "No sliver present." && exit # programs # XXX check consistency for variables {} SED=/bin/sed SEDOPT=-r [ -x ${SED} ] || { SED=`which sed` ; SEDOPT=-E ; } IPFW=/sbin/ipfw IPFW_CHECK="/sbin/ipfw -n" debug() { # $1 message to be displayed [ 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 } 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 in case of error release_lock echo "ipfw-be aborting (netconfig help): $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' } # 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} -q table $SLICE_TABLE flush #${IPFW} delete ${IPFW_RULE_MIN}-${IPFW_RULE_MAX} #${IPFW} pipe delete ${IPFW_PIPE_MIN}-${IPFW_PIPE_MAX} # since all rules are now deleted, we should initialize the firewall ipfw_init } # # 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 # # the new_rule variable is set if the rule to be installed is new # we need to know this because we do not want to clean # rule counters on pipes reconfiguration add_rule() { # slice_id new_rule type arg ipfw_rule pipe_index timeout local slice_id=$1 new_rule=$2 type=$3 arg=$4 local ipfw_rule=$5 pipe_index=$6 timeout=$7 local ipfw_pipe_in ipfw_pipe_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" # find actual pipe numbers ipfw_pipe_in=$(($IPFW_PIPE_MIN + $((2 * $(($pipe_index - 1)))) )) ipfw_pipe_out=$(($ipfw_pipe_in + 1)) local del # used delete incompatible configurations # first, call ipfw -n to check syntax, if ok move on and do the action 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 ${ipfw_pipe_in} in jail $slice_id ${rule_in} // $type $arg" rule_out="pipe ${ipfw_pipe_out} out jail $slice_id ${rule_out} // $type $arg" ${IPFW_CHECK} add ${ipfw_rule} $rule_in > /dev/null || \ abort "ipfw syntax error $rule_in" ${IPFW_CHECK} add ${ipfw_rule} $rule_out > /dev/null || \ abort "ipfw syntax error $rule_out" fi # check error reporting ${IPFW_CHECK} pipe ${ipfw_pipe_in} config ${CONFIG_PIPE_IN} > /dev/null || \ abort "ipfw syntax error pipe_in" ${IPFW_CHECK} pipe ${ipfw_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 0 $slice_id service $arg [ "$del" = "cli_ser" ] && do_delete 0 $slice_id client $arg [ "$del" = "cli_ser" ] && do_delete 0 $slice_id server $arg [ "$new_rule" != "0" ] && ${IPFW} add ${ipfw_rule} $rule_in > /dev/null [ "$new_rule" != "0" ] && ${IPFW} add ${ipfw_rule} $rule_out > /dev/null # config pipes ${IPFW} pipe ${ipfw_pipe_in} config ${CONFIG_PIPE_IN} ${IPFW} pipe ${ipfw_pipe_out} config ${CONFIG_PIPE_OUT} # send output to the user ${IPFW} show ${ipfw_rule} ${IPFW} pipe ${ipfw_pipe_in} show ${IPFW} pipe ${ipfw_pipe_out} show #add test [ "$TEST" = "1" ] && return # add to the database ( grep -v -- "^${slice_id} ${type} ${arg} " $DBFILE; \ echo "${slice_id} ${type} ${arg} ${ipfw_rule} ${pipe_index} ${timeout}" ) > ${DBFILE}.tmp mv ${DBFILE}.tmp ${DBFILE} } # # Delete a given configuration # if block_deletion !0 free block resources (if necessary) # otherwise leave the block allocated in case # we are adding the first rule do_delete() { # block_deletion slice_id type arg local ipfw_pipe_in ipfw_pipe_out pipe_index ipfw_rule local block_deletion=$1 slice_id=$2 type=$3 arg=$4 [ "${type}" = "BLOCK" ] && abort "A Block can not be deleted" [ "${arg}" = "" ] && abort "Missing args on 'delete', expected on of {SERVICE|SERVER|CLIENT} port_number" set `find_rule $slice_id $type $arg` ipfw_rule=$1; pipe_index=$2 [ "$ipfw_rule" = "0" ] && return # no rules found # find actual pipe numbers XXX do as function ipfw_pipe_in=$(($IPFW_PIPE_MIN + $((2 * $(($pipe_index - 1)))) )) ipfw_pipe_out=$(($ipfw_pipe_in + 1)) echo "removing configuration ${slice_id} ${type} ${arg}" [ "$TEST" = "1" ] && return 0 $IPFW delete ${ipfw_rule} $IPFW pipe delete ${ipfw_pipe_in} $IPFW pipe delete ${ipfw_pipe_out} # remove from the database grep -v -- "^${slice_id} ${type} ${arg} " $DBFILE > ${DBFILE}.tmp mv ${DBFILE}.tmp ${DBFILE} # if there are no mor rules for the user # remove the table entry from ipfw and from the db [ $block_deletion = 0 ] && return 0 local rule_counter=`grep ^${slice_id} ${DBFILE} | wc -l` [ $rule_counter -gt 1 ] && return 0 # there are still user rules # delete the block and clean the table local block_n=`grep "^${slice_id} BLOCK" ${DBFILE} | cut -d " " -f 3` debug "Deleting BLOCK <${block_n}> entry from ipfw and from the database" table_remove $slice_id $block_n } # # compare the argument with the first two field of # the database. # On match returns the block number, otherwise returns 0. # no echo inside find_block() { # $1 slice_id local ret ret=`grep -- "^$1 BLOCK " $DBFILE` [ x"$ret" = x ] && echo "0" && return # nothing found # ignore multiple matches. If the db is corrupt we are # screwed anyways set $ret echo "$3" } # # remove the default user rule and # the a BLOCK entry from ipfw and update the db # no echo inside table_remove() { # $slice_id $block_n [ "$TEST" = "1" ] && return 0 # compute and delete the last user rule local ipfw_rulemax=$(($IPFW_RULE_MIN + $(($M *${block_n})) -1)) ${IPFW} table $SLICE_TABLE delete $slice_id ${IPFW} delete ${ipfw_rulemax} ( grep -v -- "^${slice_id} BLOCK ${block_n}" $DBFILE; ) > ${DBFILE}.tmp mv ${DBFILE}.tmp ${DBFILE} return 0 } # # find a rule and pipes # allocate a new block if no rules are found. # # Return ipfw_rule, index_pipe and new_rule # new_rule is a flag set if the rule was not found # # return 0 as first argument if there are no resource available find_allocate() { # slice_id type arg local slice_id=$1 type=$2 arg=$3 local ipfw_rule pipe_index new_block=0 # search for already allocated rule and pipes set `find_rule $slice_id $type $arg` ipfw_rule=$1; pipe_index=$2 [ ! ${ipfw_rule} = 0 ] && echo $ipfw_rule $pipe_index "0" && return 0 # rules found, return # no rules found, search for an already allocated block # if not found, allocate a new block local block_n=`find_block ${slice_id}` [ ${block_n} = "0" ] && new_block=1 && block_n=`allocate_block` [ ${block_n} = "0" -o ${block_n} -gt $BLOCK_MAX ] && echo 0 && return 0; # here we have a valid block id # compute the user block ruleset local ipfw_rulemin=$(($IPFW_RULE_MIN + $(($M *$(($block_n - 1)))))) local ipfw_rulemax=$(($(($ipfw_rulemin + $M)) - 1 )) # find rule and pipes, we reserve the last rule to the user default rule set `allocate_resources $ipfw_rulemin $(($ipfw_rulemax - 1))` ipfw_rule=$1; pipe_index=$2 [ $ipfw_rule = 0 ] && echo 0 && return 0 # no resources # configure the table, add the last user rule and update the database if [ "$TEST" = "0" -a $new_block = 1 ] ; then ${IPFW} table $SLICE_TABLE add ${slice_id} ${ipfw_rulemin} > /dev/null ${IPFW} add ${ipfw_rulemax} allow all from any to any > /dev/null ( echo "${slice_id} BLOCK ${block_n}" ) >> ${DBFILE} fi echo $ipfw_rule $pipe_index "1" return 0 } # # called with the database file as input # compare the tuple with # the current firewall configuration. The database contains # slice_id type arg ipfw_rule pipe_index timeout # On match returns # On non match returns 0 0 0 # no echo inside find_rule() { # slice_id type arg local ret ret=`grep -- "^$1 $2 $3 " $DBFILE | grep -v BLOCK` [ 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 # within a block # Returns r=0 if there are no resources available # no echo inside allocate_resources() { # ipfw_minrule ipfw_maxrule local p r # remove comments, extract field, sort p=`grep -v '^#' $DBFILE | grep -v BLOCK | awk '{print $5}' | sort -n | \ find_hole $PIPE_MIN $PIPE_MAX` r=`grep -v '^#' $DBFILE | grep -v BLOCK | awk '{print $4}' | sort -n | \ find_hole $1 $2` [ $r = 0 -o $p = 0 ] && r=0 # no resources available echo $r $p } # # allocate a free block # Returns 0 if there are no resources available # no debug inside allocate_block() { b=`grep -v '^#' $DBFILE | grep BLOCK | awk '{print $3}' | sort -n | \ find_hole $BLOCK_MIN $BLOCK_MAX` echo $b } # # parse the ipfw database and remove expired rules # # Each timeout value stored in the database is compared against # the current time. If the timeout is older than current, # the rules and related pipes will be deleted. kill_expired() { # slice_id type arg local match timeout # if there is no database file exit [ ! -f ${DBFILE} ] && return 0 # Get the current time now=`date -u +%s` cp ${DBFILE} ${DBFILE}.kill cat ${DBFILE}.kill | grep -v BLOCK | while read line; do match=`echo $line|cut -d " " -f 1-3` timeout=`echo $line|cut -d " " -f 6` [ $now -gt $timeout ] && do_delete 1 $match done rm ${DBFILE}.kill } # # execute functions from root context # can be used from root context as follow: # echo "super $command $args" | /vsys/ipfw-be 0 do_super() { # $arguments... case $1 in init) ipfw_init; return 0 ;; dbcleanup) clean_db; return 0 ;; killexpired) kill_expired; return 0 ;; *) abort "Invalid super command" ;; esac } # # refresh the rule timeout do_refresh() { # slice_id type arg timeout local ipfw_pipe_in ipfw_pipe_out pipe_index local slice_id=$1 type=$2 arg=$3 timeout=$4 debug "do_refresh type: <$type> arg: <$arg> timeout: <$timeout>" [ "${type}" = "BLOCK" ] && abort "BLOCK rule not valid" [ "${timeout}" = "" ] && abort "Missing args on 'refresh', expected on of {SERVICE|SERVER|CLIENT} port_number" set `find_rule $slice_id $type $arg` ipfw_rule=$1; pipe_index=$2 [ "${ipfw_rule}" = "0" ] && debug "no rules found" && return 0 # no rules found [ "$TEST" = "1" ] && return # update the database with the new timeout value ( grep -v -- "^${slice_id} ${type} ${arg} " $DBFILE; \ echo "${slice_id} ${type} ${arg} ${ipfw_rule} ${pipe_index} ${timeout}" ) > ${DBFILE}.tmp mv ${DBFILE}.tmp ${DBFILE} echo "refreshed timeout for rule ${type} ${arg}" } # # 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_OUT # show {rules|pipes} [args] # delete type arg # refresh type arg [-t timeout] # # 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 cmd=$1 ; shift local debug_args="$*"; local type=$1 ; shift local args="$*" debug "Received command: <$cmd> arguments: <$debug_args>" # set the timeout value # if present, extract the '-t timeout' substring from the command line timeout=`echo ${args} | ${SED} ${SEDOPT} 's/(.+)( -t [a-zA-Z0-9]+ )(.*)/\2/'` # if the '-t timeout' is specified, use the timeout provided by the user if [ "${timeout}" != "${args}" ] ; then # match # remove the '-t ' option timeout=`echo ${timeout} | ${SED} ${SEDOPT} 's/-t //'` timeout=`check_timeout ${timeout}` [ $timeout = 0 ] && abort "Date format $1 not valid" # clean the arguments args=`echo ${args} | ${SED} ${SEDOPT} 's/(.+)( -t [a-zA-Z0-9]+ )(.*)/\1 \3/'` else # use the default value, no need to check for correctness, no need to clean arguments timeout=`date --date="1day" +%s` # default to 1 day fi # if the table rule is not present, add it local table_rule=`${IPFW} show $S | grep "skipto tablearg" | grep "lookup jail $SLICE_TABLE"` [ -z "$table_rule" ] && ipfw_init debug "Timeout $timeout" # Handle special requests: show and delete case x"$cmd" in 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 abort "'config' should be followed by {server|client|service}" ;; x"delete") do_delete 1 $SLICE_ID $type $args ;; x"refresh") do_refresh $SLICE_ID $type $args $timeout && return 0 ;; x"show") # XXX filter out sliver rules [ "$type" = "rules" ] && ${IPFW} show && return 0 [ "$type" = "pipes" ] && ${IPFW} pipe show && return 0 abort "'show' should be followed by {rules|pipes}" ;; x"super") [ $SLICE_ID = 0 ] && do_super $type $args && return 0 abort "no permission for ipfw-be super execution" ;; x"help") do_help && return 0 ;; *) # 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" ] && echo 0 && return echo $tt } 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: ${slice_id} type: ${type} port: ${arg}" set `find_allocate ${slice_id} ${type} ${arg}` local ipfw_rule=$1 pipe_index=$2 new_rule=$3 [ ${ipfw_rule} = 0 ] && abort "No resources available" debug "Found or allocated resources ipfw_rule: ${ipfw_rule} and pipe_index: ${pipe_index}" add_rule $slice_id $new_rule $type $arg $ipfw_rule $pipe_index $timeout hook_call $type $port $rule_base $pipe_base $timeout return 0; # link configured, exit } # # 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 } # # initialize the firewall with PlanetLab default rules ipfw_init() { ${IPFW} -q delete $S ${IPFW} -q delete $D ${IPFW} add $S skipto tablearg lookup jail $SLICE_TABLE ${IPFW} add $D allow all from any to any } # # if present, call a hook function # Arguments are: # slice_id type port rule_base pipe_base timeout hook_call() { if [ -n "${HOOK}" -a -x "${HOOK}" ]; then debug "Calling the hook function." ${HOOK} ${SLICE_ID} "$*" & fi } do_help() { cat << EOF Usage: ./neconfig [SERVER|CLIENT|SERVICE] port [-t timeout] \ PIPE_IN PIPE_OUT ./netconfig show [rules|pipes] ./netconfig delete [SERVER|CLIENT|SERVICE] port ./netconfig refresh [-t timeout] [SERVER|CLIENT|SERVICE] port 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 pipe configuration, both for the upstream and downstream link, follow the dummynet syntax. A quick and not exaustive example of the parameters that can be used to configure the delay, the bandwidth and the packet loss rate for a link follow: PIPE_IN|PIPE_OUT delay 100ms bw 1Mbit/s plr 0.1 The full documentation is on the manpage[1]. The timeout value follow the linux 'date' command format[2] and can be specified as follow: 1week 2hours 3days --- References: [1] http://www.freebsd.org/cgi/man.cgi?query=ipfw [2] http://linuxmanpages.com/man1/date.1.php EOF } # ALLOCATION OF RULES AND PIPES # The ruleset is composed by different sections, as follow: # - a first set of rules is reserved and is configurable by # the root context only; # - the skipto rule (S), used to optimize the slice rule search; # - a second block of reserved rules; # - a default (D) rule for the generic configuration; # - the slice reserved rules, a block of M rules for each slice; # - the firewall default rule. # # To summarize: # 1...S-1 first block of reserved rules # S skipto tablearg lookup jail 1 # S+1..D-1 ... second block of reserved rules # D allow ip from any to any # # RULE_BASE # RULE_BASE+M # ... # # Out of 64k rules, we allocate a block of M=50 consecutive # rules to each slice using emulation. Within this block, # each configuration uses one rule number and two pipes. # # Pipes are allocated starting from PIPE_BASE, a couple # of pipes for each configuration. # # DATABASE FORMAT # The database is stored on a file, and contains # one line per record with this general structure # XID TYPE arg1 arg2 ... # whitespace separates the fields. arg1, arg2, ... # have different meaning depending on the type. # # In the database we have the following records: # - one entry for each slice that has active emulation entries. # For each of these slices we reserve a block of M ipfw rules # starting at some RULE_BASE rule number. # The database entry for this info has the form # XID BLOCK block_index # where blocks are numbered sequentially from 1. # The actual ipfw rule numbers for the block are the M rules starting at: # IPFW_RULE_MIN + (M-1)*(block_number) # # - one entry for each predefined config (CLIENT, SERVER, SERVICE). # The database entry for this info has the form # XID {CLIENT|SERVER|SERVICE} arg ipfw_rule pipe_index # ipfw_rule is the unique ipfw rule number used for this configuration # (it must be within the block of M rule indexes allocated to the slice) # pipe_index is the index of the couple of pipes used for the # configuration. pipe_index starts from 1. The actual pipes are # ipfw_pipein = IPFW_PIPE_MIN + 2*(pipe_index-1) # ipfw_pipeout = ipfw_pipein + 1 # #-- main starts here debug "--- $0 START for $SLICENAME ---" # If the db does not exist, create it and 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 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