From bb379118eaac7057a8deeea299c6edc9429f9fdd Mon Sep 17 00:00:00 2001 From: Marta Carbone Date: Mon, 11 Jan 2010 10:06:35 +0000 Subject: [PATCH] Code cleanup and integration of the cleanup expired function. --- exec/ipfw-be | 434 ++++++++++++++++++++++++++++----------------------- 1 file changed, 240 insertions(+), 194 deletions(-) diff --git a/exec/ipfw-be b/exec/ipfw-be index 801f041..239a923 100755 --- a/exec/ipfw-be +++ b/exec/ipfw-be @@ -69,34 +69,24 @@ 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, -# rules and pipes -# The index rule numbers allocated to a slice can be computed -# with the following formula: -# index_min_rule = $(($RULE_BASE + $(($M*$block_n)))) -# where block_n is the block number associated with the slice -# and M is the block size. +# 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 -RULE_BASE=10001 # the hightest rule is RULE_BASE + (M*BLOCK_MAX) PIPE_MIN=1 PIPE_MAX=25000 + # These are the actual rule numbers used in ipfw IPFW_RULE_MIN=10000 -IPFW_RULE_MAX=59999 IPFW_PIPE_MIN=10000 -IPFW_PIPE_MAX=59999 -# The mapping between keys and ipfw configuration number follow: -# rule_nr 10001..20000 are mapped to ipfw_rules 50000..59999 (n+39999) -# pipe_nr 1..25000 are mapped to ipfw_pipes 10000-59999 (n*2+9998) -# Rule index can be mapped to ipfw rules with the following formula: -# ipfw_rule = $(($index_rule + 39999)) -# Pipes index can be mapped to ipfw pipes with: -# ipfw_pipein = $(($index_pipe + $index_pipe + 9998)) -# ipfw_pipeout = $(($ipfw_pipein + $1)) -# -# the skipto and the generic default rule + +# 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 @@ -105,11 +95,8 @@ D=2000 # default rule for reserved section # set slicename and slice_id # these are the credential of the user invoking the backend SLICENAME=$1 -if [ $SLICENAME = 0 ]; then - SLICE_ID=0 -else - SLICE_ID=`id -u $SLICENAME` -fi +SLICE_ID=`id -u $SLICENAME` +[ x"$SLICE_ID" = x"" ] && echo "No sliver present." && exit # programs # XXX check consistency for variables {} @@ -159,31 +146,38 @@ clean_db() { # 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} + ${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 -add_rule() { # new_rule type arg rule pipe_base timeout - local new_rule=$1 type=$2 arg=$3 - local rule_base=$4 pipe_base=$5 timeout=$6 - local pipe_in pipe_out rule_in rule_out check_timeout +# +# 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 + # [ "$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 - pipe_in=$(($pipe_base + $pipe_base + 9998)) - pipe_out=$(($pipe_in + 1)) - local del # anything to delete ? - local rule_nr=$(($rule_base + 39999)) # formula for individual rules if [ x"$new_rule" != x"0" ] ; then case $type in server) @@ -206,74 +200,89 @@ add_rule() { # new_rule type arg rule pipe_base timeout ;; esac - rule_in="pipe ${pipe_in} in jail $SLICE_ID ${rule_in} // $type $arg" - rule_out="pipe ${pipe_out} out jail $SLICE_ID ${rule_out} // $type $arg" - ${IPFW_CHECK} add ${rule_nr} $rule_in > /dev/null || \ + 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 ${rule_nr} $rule_out > /dev/null || \ + ${IPFW_CHECK} add ${ipfw_rule} $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 || \ + ${IPFW_CHECK} pipe ${ipfw_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 || \ + ${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 $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 + [ "$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 ${pipe_in} config ${CONFIG_PIPE_IN} - ${IPFW} pipe ${pipe_out} config ${CONFIG_PIPE_OUT} + ${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 ${rule_nr} - ${IPFW} pipe ${pipe_in} show - ${IPFW} pipe ${pipe_out} show + ${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} ${rule_base} ${pipe_base} ${timeout}" ) > ${DBFILE}.tmp + ( 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 -do_delete() { # type arg - local pipe_in pipe_out pipe_base rule_base rule_nr - local type=$1 arg=$2 +# 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` - 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 + 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 + grep -v -- "^${slice_id} ${type} ${arg} " $DBFILE > ${DBFILE}.tmp mv ${DBFILE}.tmp ${DBFILE} - # XXX if the use block is empty + # if there are no mor rules for the user # remove the table entry from ipfw and from the db - # not yet implemented + [ $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` @@ -285,15 +294,78 @@ find_block() { # $1 slice_id 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 rule_base pipe_base timeout -# On match returns +# slice_id type arg ipfw_rule pipe_index timeout +# On match returns # On non match returns 0 0 0 -find_rule() { # $1 slice_id $2 type $3 arg +# no echo inside +find_rule() { # slice_id type arg local ret - ret=`grep -- "^$1 $2 $3 " $DBFILE` + 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 @@ -302,7 +374,7 @@ find_rule() { # $1 slice_id $2 type $3 arg 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 @@ -317,10 +389,12 @@ find_hole() { # min max 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 -allocate_resources() { +# 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 | \ @@ -331,6 +405,41 @@ allocate_resources() { 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: @@ -343,66 +452,44 @@ do_super() { # $arguments... dbcleanup) clean_db; return 0 ;; + killexpired) + kill_expired; return 0 + ;; *) abort "Invalid super command" ;; esac } -# -# show ipfw rules and pipes filtering on slice_id -# If the first argument is 0 filter rules, -# otherwise filter pipes -do_show() { #$1 show rules or pipes - local list ipfw_list - - if [ $1 == "0" ]; then - list=`grep "^$SLICE_ID " $DBFILE | grep -v BLOCK | cut -d " " -f 4` - for i in $list; do ipfw_list="$ipfw_list $(($i + 39999))"; done - [ -n "${ipfw_list}" ] && ${IPFW} show $ipfw_list - else - # ipfw pipe show does not selectively filter pipes - # XXX so leave this code commented and show all pipes - #list=`grep "^$SLICE_ID " $DBFILE | grep -v BLOCK | cut -d " " -f 5` - # the pipe list is build adding two ipfw pipes for each pipe index - #for i in $list; do ipfw_list="$ipfw_list $(($i + $i + 9998)) $(($i + $i + 9998 +1)) "; done - #[ -n "${ipfw_list}" ] && ${IPFW} pipe show $ipfw_list - ${IPFW} pipe show - fi -} - # # refresh the rule timeout -do_refresh() { # type arg timeout - local pipe_in pipe_out pipe_base rule_base rule_nr - local type=$1 arg=$2 timeout=$3 +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` - rule_base=$1; pipe_base=$2 - [ "${rule_base}" = "0" ] && debug "no rules found" && return 0 # no rules found - - rule_nr=$(($rule_base + 39999)) # XXX only individual rules - pipe_in=$(($pipe_base + $pipe_base + 9998)) - pipe_out=$(($pipe_in + 1)) - debug "ipfw rule and pipes value: rule: <$rule_nr> pipe in: <$pipe_in> pipe_out: <$pipe_out>" + 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} ${rule_base} ${pipe_base} ${timeout}" ) > ${DBFILE}.tmp + ( 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. @@ -411,7 +498,6 @@ do_refresh() { # type arg timeout 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 @@ -421,11 +507,12 @@ process() { # 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 user define timeout value + # 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 //'` - check_timeout ${timeout} # abort on error + 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 @@ -433,24 +520,29 @@ process() { 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 $timeout $type $args && return 0 - [ "$type" = "client" ] && do_config $timeout $type $args && return 0 - [ "$type" = "service" ] && do_config $timeout $type $args && return 0 + [ "$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 ${SLICE_ID} $type $args + do_delete 1 $SLICE_ID $type $args ;; x"refresh") - do_refresh $type $args $timeout && return 0 + do_refresh $SLICE_ID $type $args $timeout && return 0 ;; x"show") - [ "$type" = "rules" ] && do_show 0 && return 0 - [ "$type" = "pipes" ] && do_show 1 && return 0 + # 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") @@ -470,10 +562,12 @@ process() { # validate the timeout check_timeout() { # timeout local tt=`date --date="${1}" +%s` - [ "$?" != "0" ] && abort "Date format $1 not valid" + [ "$?" != "0" ] && echo 0 && return + echo $tt } -do_config() { # timeout type arg PIPE_IN pipe_conf PIPE_OUT pipe_conf +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 @@ -512,70 +606,17 @@ do_config() { # timeout type arg PIPE_IN pipe_conf PIPE_OUT pipe_conf 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 found, just changing the pipe configuration" - add_rule $new_pipe $type $arg $rule_base $pipe_base $timeout - hook_call $type $port $rule_base $pipe_base $timeout - return 0; # link configured, exit - fi - - debug "link not found, search for a block already allocated to the user" - - # Search if there is a block already allocated to the slice_id - set `find_block ${SLICE_ID}` - local block_n=$1 - if [ ${block_n} = "0" ] ; then - debug "Block not found, allocate a new block" - # blocks are allocated in sequence, get the first free - block_n=`grep BLOCK $DBFILE | tail -1 | cut -d " " -f 3` - if [ -z $block_n ]; then - block_n=$(($BLOCK_MIN - 1)) - fi - RULE_IN_MIN=$(($RULE_BASE + $(($M*$block_n)))) - block_n=$(($block_n +1)) - debug "Allocated new block $block_nr to user $SLICE_ID" - [ $block_n -gt $BLOCK_MAX ] && abort "no block resources available" - - # add the rule into the firewall table. - # note that the rule number into the table are not database number, - # so we need to compute the firewall number before the table insertion - local ipfw_rule_nr=$(($RULE_IN_MIN + 39999)) # XXX formula for individual rules - debug "Configuring table: <${IPFW_CHECK} table $SLICE_TABLE add ${SLICE_ID} ${ipfw_rule_nr}>" - ${IPFW_CHECK} table $SLICE_TABLE add ${SLICE_ID} ${rule_nr} > /dev/null || \ - abort "ipfw syntax error $rule_out" - ${IPFW} table $SLICE_TABLE add ${SLICE_ID} ${ipfw_rule_nr} > /dev/null - - [ "$TEST" = "1" ] && return - # add the block declaration to the database - ( grep -v -- "^${SLICE_ID} BLOCK " $DBFILE; \ - echo "${SLICE_ID} BLOCK ${block_n}" ) > ${DBFILE}.tmp - mv ${DBFILE}.tmp ${DBFILE} - else - debug "Block $block_n found for user $SLICE_ID" - fi - - RULE_IN_MAX=$(($RULE_BASE + $(($M * $block_n)))) - RULE_IN_MIN=$(($RULE_IN_MAX - $M)) - debug "Block $block_n, with rules <${RULE_IN_MIN}:${RULE_IN_MAX}>" - debug "Corresponding to ipfw rules <$(($RULE_IN_MIN + 39999)):$(($RULE_IN_MAX + 39999))>" - debug "where the last rule number belongs to the next slice." + debug "Search for slice_id: ${slice_id} type: ${type} port: ${arg}" - new_pipe=1 - set `allocate_resources $RULE_IN_MIN $RULE_IN_MAX` - rule_base=$1; pipe_base=$2 + set `find_allocate ${slice_id} ${type} ${arg}` + local ipfw_rule=$1 pipe_index=$2 new_rule=$3 - [ $rule_base = 0 ] && abort "no resources available" - debug "found free resources rule: $rule_base pipe: $pipe_base" + [ ${ipfw_rule} = 0 ] && abort "No resources available" + debug "Found or allocated resources ipfw_rule: ${ipfw_rule} and pipe_index: ${pipe_index}" - add_rule $new_pipe $type $arg $rule_base $pipe_base $timeout + 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 } # @@ -598,6 +639,8 @@ release_lock() { # # 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 } @@ -608,6 +651,7 @@ ipfw_init() { # 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 } @@ -704,24 +748,26 @@ EOF # 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_number +# XID BLOCK block_index # where blocks are numbered sequentially from 1. -# The actual rule number is RULE_BASE + M*(block_number) -# (we don't care if we waste some rules) +# 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 rule_nr pipe_index -# rule_nr is the absolute rule number for this configuration -# (it must be within the block of M rules allocated to the slice) +# 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. +# 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 we clean rules and pipes +# 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 -- 2.43.0