3 # Marta Carbone, Luigi Rizzo
4 # Copyright (C) 2009 Universita` di Pisa
7 # This script the vsys backend used to configure emulation.
9 # - reads the user's input from the vsys input pipe
10 # - validates the input
11 # - configures the firewall
12 # - writes results on the output vsys pipe
14 # Configurable variables are at the beginning
16 # If HOOK is set the program is called before configuring a rule.
17 # A sample hook can be found in the ipfwroot.rpm package,
18 # it can be used to collect statistical information on dummynet usage.
19 # To configure an hook, set the HOOK variable as follow:
20 # HOOK=/tmp/sample_hook
22 # You should not touch anything below.
24 # We assume three type of connections
25 # SERVER we know the local port P, and do the
26 # bind/listen/accept on the local socket.
27 # pipe_in in dst-port P
28 # pipe_out out src-port P
30 # CLIENT we know the remote port P, and do a connect to it
31 # (src and dst are swapped wrt the previous case)
32 # pipe_in in src-port P
33 # pipe_out out dst-port P
35 # SERVICE we run a server on local port P, and also connect
36 # from local clients to remote servers on port P.
37 # pipe_in in { dst-port P or src-port P }
38 # pipe_out out { src-port P or dst-port P }
40 # On a given port a user can have one CLIENT and/or one SERVER
41 # configuration or one SERVICE configuration.
42 # When a SERVICE configuration is installed any existing CLIENT
43 # and SERVER configuration on the same port are removed.
44 # When a CLIENT or SERVER configuration is installed any existing
45 # SERVICE configuration on the same port is removed.
47 # The following is a case that is implemented as SERVER
48 # D we run a server on local port P, and also connect
49 # to remote servers but doing a bind(P) before connect().
50 # In terms of rules, this is not distinguishable from
51 # the SERVER case, however it would be different if we
52 # had a way to tell SERVER from CLIENT sockets
53 # pipe_in in dst-port P
54 # pipe_out out src-port P
56 # The database of current ipfw and dummynet configuration is in a
57 # file which is regenerated on errors. The format is
59 # slice_id type arg rule_base pipe_base timeout
61 # (lines starting with '#' are comments and are ignored)
62 # For each configuration we allocate one rule number in ipfw,
63 # and two sequential pipe numbers.
65 # globals, do not touch below
66 VERBOSE=0 # set to !0 to enable debug messages
67 TEST=0 # set to 1 for test mode
70 lockfile=/var/lock/ipfw.lock
72 # These values are the keys used in the database for blocks
73 # and pipes. For rules we store directly the ipfw number.
75 # For each user we allocate a block of $M rules. The rules
76 # allocated to users are within the range:
77 # ipfw_min_rule = RULE_BASE
78 # ipfw_max_rule = RULE_BASE + ((M-1)*block_n) -1
85 # These are the actual rule numbers used in ipfw
89 # The skipto and the generic default rule
90 # these values are used to initialize the firewall
91 SLICE_TABLE=1 # table number used for slice ids lookup
92 S=1000 # firewall rule number for the skipto rule
93 D=2000 # default rule for reserved section
95 # set slicename and slice_id
96 # these are the credential of the user invoking the backend
98 SLICE_ID=`id -u $SLICENAME`
99 [ x"$SLICE_ID" = x"" ] && echo "No sliver present." && exit
102 # XXX check consistency for variables {}
105 [ -x ${SED} ] || { SED=`which sed` ; SEDOPT=-E ; }
107 IPFW_CHECK="/sbin/ipfw -n"
109 debug() { # $1 message to be displayed
110 [ x"${VERBOSE}" != x"0" ] && echo "ipfw-be: $1"
113 # if the first argument is -v, enable verbose mode
115 [ x"$1" = x"-v" -o x"$2" = x"-v" ] && VERBOSE=1
119 [ x"$1" = x"-q" -o x"$2" = x"-q" ] || return
121 IPFW="/bin/echo ipfw:"
122 IPFW_CHECK="/bin/echo ipfw -n:"
125 abort() { # $1 message to be displayed in case of error
127 echo "ipfw-be aborting (netconfig help): $1"
131 # remove dangerous characters from user input
132 # if present, the leading '-v/-t' will be removed
133 filter() { # $* variables to be filtered
134 [ x${1} = x"-v" -o x${1} = x"-q" ] && shift
135 [ x${1} = x"-v" -o x${1} = x"-q" ] && shift
136 # allowed chars are: numbers, uppercase and lowercase letters,
137 # spaces, and the following symbols: .,_-/
138 echo "$*" | ${SED} ${SEDOPT} 's/[^\t0-9a-zA-Z., _\/\{}-]*//g'
141 # remove all entries from the ipfw config, and create an empty db
145 # we would like to delete ranges of rules and pipes but this
146 # is not supported so for the time being we kill them all
148 ${IPFW} -q pipe flush
149 ${IPFW} -q table $SLICE_TABLE flush
150 #${IPFW} delete ${IPFW_RULE_MIN}-${IPFW_RULE_MAX}
151 #${IPFW} pipe delete ${IPFW_PIPE_MIN}-${IPFW_PIPE_MAX}
152 # since all rules are now deleted, we should initialize the firewall
157 # Add the ipfw rule/pipe and update the database.
158 # The pipe-in and pipe_out config are through global variables
159 # CONFIG_IN CONFIG_OUT because they may be long.
160 # Other arguments are on the command line
162 # the new_rule variable is set if the rule to be installed is new
163 # we need to know this because we do not want to clean
164 # rule counters on pipes reconfiguration
165 add_rule() { # slice_id new_rule type arg ipfw_rule pipe_index timeout
166 local slice_id=$1 new_rule=$2 type=$3 arg=$4
167 local ipfw_rule=$5 pipe_index=$6 timeout=$7
168 local ipfw_pipe_in ipfw_pipe_out check_timeout
170 # If we use a profile file, locate the user directory
171 # move in the slice root dir XXX todo
172 # [ "$TEST" != "1" ] && cd /vservers/${SLICENAME}/root
173 #echo ${CONFIG_STRING} | ${SED} -e "s/ profile \(.[^ ]\)/ profile \/vservers\/${SLICENAME}\/\1/g"
175 # find actual pipe numbers
176 ipfw_pipe_in=$(($IPFW_PIPE_MIN + $((2 * $(($pipe_index - 1)))) ))
177 ipfw_pipe_out=$(($ipfw_pipe_in + 1))
178 local del # used delete incompatible configurations
180 # first, call ipfw -n to check syntax, if ok move on and do the action
181 if [ x"$new_rule" != x"0" ] ; then
184 rule_in="dst-port $arg"
185 rule_out="src-port $arg"
189 rule_in="src-port $arg"
190 rule_out="dst-port $arg"
194 rule_in="{ src-port $arg or dst-port $arg }"
195 rule_out="{ src-port $arg or dst-port $arg }"
199 abort "invalid service type $type"
203 rule_in="pipe ${ipfw_pipe_in} in ${rule_in} // $type $arg $slice_id"
204 rule_out="pipe ${ipfw_pipe_out} out ${rule_out} // $type $arg $slice_id"
206 ${IPFW_CHECK} add ${ipfw_rule} $rule_in > /dev/null || \
207 abort "ipfw syntax error $rule_in"
208 ${IPFW_CHECK} add ${ipfw_rule} $rule_out > /dev/null || \
209 abort "ipfw syntax error $rule_out"
212 # check error reporting
213 ${IPFW_CHECK} pipe ${ipfw_pipe_in} config ${CONFIG_PIPE_IN} > /dev/null || \
214 abort "ipfw syntax error pipe_in"
215 ${IPFW_CHECK} pipe ${ipfw_pipe_out} config ${CONFIG_PIPE_OUT} > /dev/null || \
216 abort "ipfw syntax error pipe_out"
218 # all good, delete and add rules if necessary
219 [ "$del" = "service" ] && do_delete 0 $slice_id service $arg
220 [ "$del" = "cli_ser" ] && do_delete 0 $slice_id client $arg
221 [ "$del" = "cli_ser" ] && do_delete 0 $slice_id server $arg
222 [ "$new_rule" != "0" ] && ${IPFW} add ${ipfw_rule} $rule_in > /dev/null
223 [ "$new_rule" != "0" ] && ${IPFW} add ${ipfw_rule} $rule_out > /dev/null
225 ${IPFW} pipe ${ipfw_pipe_in} config ${CONFIG_PIPE_IN}
226 ${IPFW} pipe ${ipfw_pipe_out} config ${CONFIG_PIPE_OUT}
228 # send output to the user
229 ${IPFW} show ${ipfw_rule}
230 ${IPFW} pipe ${ipfw_pipe_in} show
231 ${IPFW} pipe ${ipfw_pipe_out} show
234 [ "$TEST" = "1" ] && return
235 # add to the database
236 ( grep -v -- "^${slice_id} ${type} ${arg} " $DBFILE; \
237 echo "${slice_id} ${type} ${arg} ${ipfw_rule} ${pipe_index} ${timeout}" ) > ${DBFILE}.tmp
238 mv ${DBFILE}.tmp ${DBFILE}
242 # Delete a given configuration
243 # if block_deletion !0 free block resources (if necessary)
244 # otherwise leave the block allocated in case
245 # we are adding the first rule
246 do_delete() { # block_deletion slice_id type arg
247 local ipfw_pipe_in ipfw_pipe_out pipe_index ipfw_rule
248 local block_deletion=$1 slice_id=$2 type=$3 arg=$4
250 [ "${type}" = "BLOCK" ] && abort "A Block can not be deleted"
251 [ "${arg}" = "" ] && abort "Missing args on 'delete', expected on of {SERVICE|SERVER|CLIENT} port_number"
252 set `find_rule $slice_id $type $arg`
253 ipfw_rule=$1; pipe_index=$2
254 [ "$ipfw_rule" = "0" ] && return # no rules found
256 # find actual pipe numbers XXX do as function
257 ipfw_pipe_in=$(($IPFW_PIPE_MIN + $((2 * $(($pipe_index - 1)))) ))
258 ipfw_pipe_out=$(($ipfw_pipe_in + 1))
260 echo "removing configuration ${slice_id} ${type} ${arg}"
261 [ "$TEST" = "1" ] && return 0
262 $IPFW delete ${ipfw_rule}
263 $IPFW pipe delete ${ipfw_pipe_in}
264 $IPFW pipe delete ${ipfw_pipe_out}
265 # remove from the database
266 grep -v -- "^${slice_id} ${type} ${arg} " $DBFILE > ${DBFILE}.tmp
267 mv ${DBFILE}.tmp ${DBFILE}
269 # if there are no mor rules for the user
270 # remove the table entry from ipfw and from the db
271 [ $block_deletion = 0 ] && return 0
273 local rule_counter=`grep ^${slice_id} ${DBFILE} | wc -l`
274 [ $rule_counter -gt 1 ] && return 0 # there are still user rules
275 # delete the block and clean the table
276 local block_n=`grep "^${slice_id} BLOCK" ${DBFILE} | cut -d " " -f 3`
277 debug "Deleting BLOCK <${block_n}> entry from ipfw and from the database"
278 table_remove $slice_id $block_n
282 # compare the argument with the first two field of
284 # On match returns the block number, otherwise returns 0.
286 find_block() { # $1 slice_id
288 ret=`grep -- "^$1 BLOCK " $DBFILE`
290 [ x"$ret" = x ] && echo "0" && return # nothing found
291 # ignore multiple matches. If the db is corrupt we are
298 # remove the default user rule and
299 # the a BLOCK entry from ipfw and update the db
301 table_remove() { # $slice_id $block_n
302 [ "$TEST" = "1" ] && return 0
304 # compute and delete the last user rule
305 local ipfw_rulemax=$(($IPFW_RULE_MIN + $(($M *${block_n})) -1))
306 ${IPFW} table $SLICE_TABLE delete $slice_id
307 ${IPFW} delete ${ipfw_rulemax}
308 ( grep -v -- "^${slice_id} BLOCK ${block_n}" $DBFILE; ) > ${DBFILE}.tmp
309 mv ${DBFILE}.tmp ${DBFILE}
314 # find a rule and pipes
315 # allocate a new block if no rules are found.
317 # Return ipfw_rule, index_pipe and new_rule
318 # new_rule is a flag set if the rule was not found
320 # return 0 as first argument if there are no resource available
321 find_allocate() { # slice_id type arg
322 local slice_id=$1 type=$2 arg=$3
323 local ipfw_rule pipe_index new_block=0
325 # search for already allocated rule and pipes
326 set `find_rule $slice_id $type $arg`
327 ipfw_rule=$1; pipe_index=$2
328 [ ! ${ipfw_rule} = 0 ] && echo $ipfw_rule $pipe_index "0" && return 0 # rules found, return
330 # no rules found, search for an already allocated block
331 # if not found, allocate a new block
332 local block_n=`find_block ${slice_id}`
333 [ ${block_n} = "0" ] && new_block=1 && block_n=`allocate_block`
334 [ ${block_n} = "0" -o ${block_n} -gt $BLOCK_MAX ] && echo 0 && return 0;
336 # here we have a valid block id
337 # compute the user block ruleset
338 local ipfw_rulemin=$(($IPFW_RULE_MIN + $(($M *$(($block_n - 1))))))
339 local ipfw_rulemax=$(($(($ipfw_rulemin + $M)) - 1 ))
341 # find rule and pipes, we reserve the last rule to the user default rule
342 set `allocate_resources $ipfw_rulemin $(($ipfw_rulemax - 1))`
343 ipfw_rule=$1; pipe_index=$2
344 [ $ipfw_rule = 0 ] && echo 0 && return 0 # no resources
346 # configure the table, add the last user rule and update the database
347 if [ "$TEST" = "0" -a $new_block = 1 ] ; then
348 ${IPFW} table $SLICE_TABLE add ${slice_id} ${ipfw_rulemin} > /dev/null
349 ${IPFW} add ${ipfw_rulemax} allow all from any to any > /dev/null
350 ( echo "${slice_id} BLOCK ${block_n}" ) >> ${DBFILE}
353 echo $ipfw_rule $pipe_index "1"
359 # called with the database file as input
360 # compare the tuple <slice_id type arg> with
361 # the current firewall configuration. The database contains
362 # slice_id type arg ipfw_rule pipe_index timeout
363 # On match returns <ipfw_rule pipe_index timeout>
364 # On non match returns 0 0 0
366 find_rule() { # slice_id type arg
368 ret=`grep -- "^$1 $2 $3 " $DBFILE | grep -v BLOCK`
370 [ x"$ret" = x ] && echo "0 0 0 " && return # nothing found
371 # ignore multiple matches. If the db is corrupt we are
378 # Find a hole in a list of numbers within a range (boundaries included)
379 # The input is passed as a sorted list of numbers on stdin.
380 # Return a "0" rule if there is no rule free
381 find_hole() { # min max
382 local min=$1 cand=$1 max=$2 line
384 [ $line -lt $min ] && continue
385 [ $line -ne $cand ] && break # found
386 [ $cand -ge $max ] && cand=0 && break # no space
393 # returns a free rule and pipe base for client|server|service
395 # Returns r=0 if there are no resources available
397 allocate_resources() { # ipfw_minrule ipfw_maxrule
399 # remove comments, extract field, sort
400 p=`grep -v '^#' $DBFILE | grep -v BLOCK | awk '{print $5}' | sort -n | \
401 find_hole $PIPE_MIN $PIPE_MAX`
402 r=`grep -v '^#' $DBFILE | grep -v BLOCK | awk '{print $4}' | sort -n | \
404 [ $r = 0 -o $p = 0 ] && r=0 # no resources available
409 # allocate a free block
410 # Returns 0 if there are no resources available
413 b=`grep -v '^#' $DBFILE | grep BLOCK | awk '{print $3}' | sort -n | \
414 find_hole $BLOCK_MIN $BLOCK_MAX`
419 # parse the ipfw database and remove expired rules
421 # Each timeout value stored in the database is compared against
422 # the current time. If the timeout is older than current,
423 # the rules and related pipes will be deleted.
424 kill_expired() { # slice_id type arg
427 # if there is no database file exit
428 [ ! -f ${DBFILE} ] && return 0
430 # Get the current time
433 cp ${DBFILE} ${DBFILE}.kill
434 cat ${DBFILE}.kill | grep -v BLOCK |
436 match=`echo $line|cut -d " " -f 1-3`
437 timeout=`echo $line|cut -d " " -f 6`
438 [ $now -gt $timeout ] && do_delete 1 $match
444 # execute functions from root context
445 # can be used from root context as follow:
446 # echo "super $command $args" | /vsys/ipfw-be 0
447 do_super() { # $arguments...
456 kill_expired; return 0
459 abort "Invalid super command"
465 # refresh the rule timeout
466 do_refresh() { # slice_id type arg timeout
467 local ipfw_pipe_in ipfw_pipe_out pipe_index
468 local slice_id=$1 type=$2 arg=$3 timeout=$4
470 debug "do_refresh type: <$type> arg: <$arg> timeout: <$timeout>"
471 [ "${type}" = "BLOCK" ] && abort "BLOCK rule not valid"
472 [ "${timeout}" = "" ] && abort "Missing args on 'refresh', expected on of {SERVICE|SERVER|CLIENT} port_number"
473 set `find_rule $slice_id $type $arg`
474 ipfw_rule=$1; pipe_index=$2
475 [ "${ipfw_rule}" = "0" ] && debug "no rules found" && return 0 # no rules found
477 [ "$TEST" = "1" ] && return
478 # update the database with the new timeout value
479 ( grep -v -- "^${slice_id} ${type} ${arg} " $DBFILE; \
480 echo "${slice_id} ${type} ${arg} ${ipfw_rule} ${pipe_index} ${timeout}" ) > ${DBFILE}.tmp
481 mv ${DBFILE}.tmp ${DBFILE}
482 echo "refreshed timeout for rule ${type} ${arg}"
487 # A request is made by a set of arguments formatted as follow:
489 # config {server|client|service} arg [-t timeout] IN <pipe_conf> OUT <pipe_conf>
490 # show {rules|pipes} [args]
492 # refresh type arg [-t timeout]
494 # The timeout value is expressed as:
495 # week, day, month or anything else accepted by the date command.
496 # The id of the slice issuing the request is in the $SLICE_ID variable,
497 # set at the beginning of this script.
500 local timeout TMP i rule_base pipe_base
502 local debug_args="$*";
503 local type=$1 ; shift
505 debug "Received command: <$cmd> arguments: <$debug_args>"
507 # set the timeout value
508 # if present, extract the '-t timeout' substring from the command line
509 timeout=`echo ${args} | ${SED} ${SEDOPT} 's/(.+)( -t [a-zA-Z0-9]+ )(.*)/\2/'`
510 # if the '-t timeout' is specified, use the timeout provided by the user
511 if [ "${timeout}" != "${args}" ] ; then # match
512 # remove the '-t ' option
513 timeout=`echo ${timeout} | ${SED} ${SEDOPT} 's/-t //'`
514 timeout=`check_timeout ${timeout}`
515 [ $timeout = 0 ] && abort "Date format $1 not valid"
516 # clean the arguments
517 args=`echo ${args} | ${SED} ${SEDOPT} 's/(.+)( -t [a-zA-Z0-9]+ )(.*)/\1 \3/'`
519 # use the default value, no need to check for correctness, no need to clean arguments
520 timeout=`date --date="1day" +%s` # default to 1 day
523 # if the table rule is not present, add it
524 local table_rule=`${IPFW} show $S | grep "skipto tablearg" | grep "lookup jail $SLICE_TABLE"`
525 [ -z "$table_rule" ] && ipfw_init
527 debug "Timeout $timeout"
528 # Handle special requests: show and delete
531 [ "$type" = "server" ] && do_config $SLICE_ID $timeout $type $args && return 0
532 [ "$type" = "client" ] && do_config $SLICE_ID $timeout $type $args && return 0
533 [ "$type" = "service" ] && do_config $SLICE_ID $timeout $type $args && return 0
534 abort "'config' should be followed by {server|client|service}"
537 do_delete 1 $SLICE_ID $type $args
540 do_refresh $SLICE_ID $type $args $timeout && return 0
543 # XXX filter out sliver rules
544 [ "$type" = "rules" ] && ${IPFW} show && return 0
545 [ "$type" = "pipes" ] && ${IPFW} pipe show && return 0
546 abort "'show' should be followed by {rules|pipes}"
549 [ $SLICE_ID = 0 ] && do_super $type $args && return 0
550 abort "no permission for ipfw-be super execution"
556 # help XXX to be done
557 abort "'command' should be one of {show|config|delete|refresh|release}"
562 # validate the timeout
563 check_timeout() { # timeout
564 local tt=`date --date="${1}" +%s`
565 [ "$?" != "0" ] && echo 0 && return
569 do_config() { # slice_id timeout type arg IN pipe_conf OUT pipe_conf
570 local slice_id=$1; shift
571 local timeout=$1; shift
573 local arg=$1; shift # XXX addr not yet implemented
575 [ "$1" != "IN" ] && abort "Missing addr:port, or IN requested"
578 # read pipe in configuration
580 while [ "$1" != "" -a "$1" != "OUT" ] ; do
584 CONFIG_PIPE_IN="$i" # XXX local ?
585 [ "$CONFIG_PIPE_IN" = "" ] && abort "Missing pipe in configuration"
587 [ "$1" != "OUT" ] && abort "Missing pipe in configuration, or missing OUT"
590 # read pipe out configuration
592 while [ "$1" != "" ] ; do
596 CONFIG_PIPE_OUT="$i" # XXX local ?
597 [ "$CONFIG_PIPE_OUT" = "" ] && abort "Missing pipe out configuration"
599 debug "Configuration Required:"
600 debug "slice_id: $SLICE_ID"
603 debug "timeout: $timeout"
604 debug "IN: $CONFIG_PIPE_IN"
605 debug "OUT: $CONFIG_PIPE_OUT"
606 debug "-----------------------"
608 # check if the link is already configured
609 debug "Search for slice_id: ${slice_id} type: ${type} port: ${arg}"
611 set `find_allocate ${slice_id} ${type} ${arg}`
612 local ipfw_rule=$1 pipe_index=$2 new_rule=$3
614 [ ${ipfw_rule} = 0 ] && abort "No resources available"
615 debug "Found or allocated resources ipfw_rule: ${ipfw_rule} and pipe_index: ${pipe_index}"
617 add_rule $slice_id $new_rule $type $arg $ipfw_rule $pipe_index $timeout
618 hook_call $type $port $rule_base $pipe_base $timeout
619 return 0; # link configured, exit
623 # acquire the lock XXX check lockfile
625 [ "$TEST" = 1 ] && return
626 lockfile -s 0 -r 0 $lockfile 2> /dev/null
627 if [ $? -ne 0 ] ; then
628 echo "lock acquisition failed"
640 # initialize the firewall with PlanetLab default rules
644 ${IPFW} add $S skipto tablearg lookup jail $SLICE_TABLE
645 ${IPFW} add $D allow all from any to any
649 # if present, call a hook function
651 # slice_id type port rule_base pipe_base timeout
653 if [ -n "${HOOK}" -a -x "${HOOK}" ]; then
654 debug "Calling the hook function."
655 ${HOOK} ${SLICE_ID} "$*" &
662 ./neconfig [SERVER|CLIENT|SERVICE] port [-t timeout] \
663 IN <pipe in configuration> OUT <pipe out configuration>
664 ./netconfig show [rules|pipes]
665 ./netconfig delete [SERVER|CLIENT|SERVICE] port
666 ./netconfig refresh [-t timeout] [SERVER|CLIENT|SERVICE] port
668 We assume three type of connections
669 SERVER we know the local port P, and do the
670 bind/listen/accept on the local socket.
671 pipe_in in dst-port P
672 pipe_out out src-port P
674 CLIENT we know the remote port P, and do a connect to it
675 (src and dst are swapped wrt the previous case)
676 pipe_in in src-port P
677 pipe_out out dst-port P
679 SERVICE we run a server on local port P, and also connect
680 from local clients to remote servers on port P.
681 pipe_in in { dst-port P or src-port P }
682 pipe_out out { src-port P or dst-port P }
684 On a given port a user can have one CLIENT and/or one SERVER
685 configuration or one SERVICE configuration.
686 When a SERVICE configuration is installed any existing CLIENT
687 and SERVER configuration on the same port are removed.
688 When a CLIENT or SERVER configuration is installed any existing
689 SERVICE configuration on the same port is removed.
691 The pipe configuration, both for the upstream and downstream link,
692 follow the dummynet syntax. A quick and not exaustive example
693 of the parameters that can be used to configure the delay,
694 the bandwidth and the packet loss rate for a link follow:
696 IN|OUT delay 100ms bw 1Mbit/s plr 0.1
698 The full documentation is on the manpage[1].
700 The timeout value follow the linux 'date' command format[2]
701 and can be specified as follow:
707 [1] http://www.freebsd.org/cgi/man.cgi?query=ipfw
708 [2] http://linuxmanpages.com/man1/date.1.php
712 # ALLOCATION OF RULES AND PIPES
713 # The ruleset is composed by different sections, as follow:
714 # - a first set of rules is reserved and is configurable by
715 # the root context only;
716 # - the skipto rule (S), used to optimize the slice rule search;
717 # - a second block of reserved rules;
718 # - a default (D) rule for the generic configuration;
719 # - the slice reserved rules, a block of M rules for each slice;
720 # - the firewall default rule.
723 # 1...S-1 first block of reserved rules
724 # S skipto tablearg lookup jail 1
725 # S+1..D-1 ... second block of reserved rules
726 # D allow ip from any to any
728 # RULE_BASE <block of M entries for first user>
729 # RULE_BASE+M <block of M entry for second user ...>
732 # Out of 64k rules, we allocate a block of M=50 consecutive
733 # rules to each slice using emulation. Within this block,
734 # each configuration uses one rule number and two pipes.
736 # Pipes are allocated starting from PIPE_BASE, a couple
737 # of pipes for each configuration.
740 # The database is stored on a file, and contains
741 # one line per record with this general structure
742 # XID TYPE arg1 arg2 ...
743 # whitespace separates the fields. arg1, arg2, ...
744 # have different meaning depending on the type.
746 # In the database we have the following records:
747 # - one entry for each slice that has active emulation entries.
748 # For each of these slices we reserve a block of M ipfw rules
749 # starting at some RULE_BASE rule number.
750 # The database entry for this info has the form
751 # XID BLOCK block_index
752 # where blocks are numbered sequentially from 1.
753 # The actual ipfw rule numbers for the block are the M rules starting at:
754 # IPFW_RULE_MIN + (M-1)*(block_number)
756 # - one entry for each predefined config (CLIENT, SERVER, SERVICE).
757 # The database entry for this info has the form
758 # XID {CLIENT|SERVER|SERVICE} arg ipfw_rule pipe_index
759 # ipfw_rule is the unique ipfw rule number used for this configuration
760 # (it must be within the block of M rule indexes allocated to the slice)
761 # pipe_index is the index of the couple of pipes used for the
762 # configuration. pipe_index starts from 1. The actual pipes are
763 # ipfw_pipein = IPFW_PIPE_MIN + 2*(pipe_index-1)
764 # ipfw_pipeout = ipfw_pipein + 1
768 debug "--- $0 START for $SLICENAME ---"
770 # If the db does not exist, create it and clean rules and pipes
771 [ ! -e ${DBFILE} ] && clean_db
773 # A request to the vsys backend is composed by a single line of input
774 read REQ # read one line, ignore the rest
775 set_verbose ${REQ} # use inital -v if present
776 set_test ${REQ} # use inital -t if present
777 REQ="`filter ${REQ}`" # remove -v and -t and invalid chars
778 debug "--- processing <${REQ}>"
779 acquire_lock # critical section
782 debug "--- $0 END ---"