CC=gcc
CFLAGS=-g -O2
-all: dcookie
+all: dcookie fd_bmsocket fd_udpsocket fd_fusemount fd_tuntap fd_tos
+
+fd_tuntap: fd_tuntap.c
+ gcc fd_tuntap.c -o exec/fd_tuntap
dcookie: dcookie.c
gcc dcookie.c -o exec/dcookie
+fdpass.o: fdpass.c
+ gcc -c fdpass.c -o fdpass.o
+
+fd_bmsocket: fd_bmsocket.c fdpass.o
+ gcc fd_bmsocket.c fdpass.o -o exec/fd_bmsocket
+
+fd_udpsocket: fd_udpsocket.c fdpass.o
+ gcc fd_udpsocket.c fdpass.o -o exec/fd_udpsocket
+
+fd_fusemount: fd_fusemount.c fdpass.o
+ gcc fd_fusemount.c fdpass.o -o exec/fd_fusemount
+
+fd_tos: fd_tos.c fdpass.o
+ gcc fd_tos.c fdpass.o -o exec/fd_tos
+
clean:
rm -f exec/*
--- /dev/null
+#!/bin/sh
+SRC="/home/$1/.ssh/"
+DEST="/vservers/$1/home/$1/.ssh/"
+
+mkdir -p $DEST &> /dev/null
+
+mount | grep "on $DEST type" > /dev/null
+if [ $? -ne 0 ]; then
+ /bin/mount --bind -o ro $SRC $DEST > /dev/null
+fi
+
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+
+$|=1;
+
+my $slicename;
+my $portnumber;
+
+
+$slicename = $ARGV[0];
+$portnumber = <STDIN>;
+
+chop($portnumber);
+
+if ($portnumber!~/^\d+$/) {
+ die("$portnumber is not a port number");
+}
+
+open CMD,"/sbin/fuser -n tcp $portnumber 2>&1|";
+
+$_ = <CMD>;
+
+my @ports;
+@ports=split;
+
+if ($#ports > 0) {
+ system("cat /proc/$ports[1]/vinfo");
+ print "Please refer to http://planetflow.planet-lab.org/lookupslice.php to obtain the name corresponding to this slice.";
+}
+
+close CMD;
--- /dev/null
+#!/usr/bin/perl
+
+$|=1;
+$slice=$ARGV[0];
+$slice_ip=`cat /etc/vservers/$slice/interfaces/0/ip`;
+$src_port = <STDIN>;
+$dst_port = <STDIN>;
+
+chomp($slice_ip);
+chomp($src_port);
+chomp($dst_port);
+
+die ("Src and dst ports need to be numbers") if (($src_port=~/[^0-9]/) || ($src_port=~/[^0-9]/));
+
+$IPTABLES_CMD_1="/sbin/iptables -t nat -D PREROUTING -m tcp -p tcp -d $slice_ip --dport $src_port -j DNAT --to-destination $slice_ip:$dst_port";
+
+$IPTABLES_CMD_2="/sbin/iptables -t nat -A PREROUTING -m tcp -p tcp -d $slice_ip --dport $src_port -j DNAT --to-destination $slice_ip:$dst_port";
+
+print "Removing any previous instances of this rule: $IPTABLES_CMD_1\n";
+system($IPTABLES_CMD_1);
+
+print "Adding forwarding rule: $IPTABLES_CMD_2\n";
+system($IPTABLES_CMD_2);
+
+print "Done.\n";
--- /dev/null
+#!/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 (only HOOK so far)
+
+# If HOOK is set, ${HOOK} 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 a hook, set the HOOK variable as follow:
+# HOOK=/tmp/sample_hook
+
+#--- You should not touch anything below this line. ----
+# For documentation see ARCHITECTURE near the end of the file.
+
+#--- global variables ---
+VERBOSE=0 # set to !0 to enable debug messages
+TEST=0 # set to 1 for test mode
+
+# The database and the lock file
+DBFILE=/tmp/ff
+lockfile=/var/lock/ipfw.lock
+
+# Min and max value (inclusive) for block_index
+BLOCK_MIN=1
+BLOCK_MAX=1000
+M=50 # size of per-slice block of rules
+# Min and max value (inclusive) for pipe_index
+PIPE_MIN=1
+PIPE_MAX=25000
+
+# These are the actual rule numbers used in ipfw
+IPFW_RULE_MIN=10000 # initial per-slice rule number
+IPFW_PIPE_MIN=10000 # initial pipe number
+
+# 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 mode if -q is found
+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/-q' 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
+# rule_in rule_out because they may be long. XXX why ?
+# 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
+ local p h # used to split the argument
+
+ local h_in h_out
+ # local rule_in rule_out # XXX test if this works
+ # find actual pipe numbers
+ ipfw_pipe_in=$(($IPFW_PIPE_MIN + $((2 * $(($pipe_index - 1)))) ))
+ ipfw_pipe_out=$(($ipfw_pipe_in + 1))
+ local del # used to delete incompatible configurations
+
+ # split the argument, and prepare PORTLIST (p) and ADDRLIST (h)
+ p=`echo $arg | cut -s -d "@" -f1-` # empty if no separator
+ if [ "$p" = "" ] ; then
+ p=$arg
+ else
+ p=`echo $arg | cut -d "@" -f1`
+ h=`echo $arg | cut -d "@" -f2`
+ fi
+
+ if [ "$h" = "" ] ; then
+ h_in=""
+ h_out=""
+ else
+ h_in=" src-ip ${h} "
+ h_out=" dst-ip ${h} "
+ fi
+
+ # 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|server)
+ rule_in="dst-port $p"
+ rule_out="src-port $p"
+ del=service
+ ;;
+ CLIENT|client)
+ rule_in="src-port $p"
+ rule_out="dst-port $p"
+ del=service
+ ;;
+ SERVICE|service)
+ rule_in="{ src-port $p or dst-port $p }"
+ rule_out="{ src-port $p or dst-port $p }"
+ del="cli_ser"
+ ;;
+ *)
+ abort "invalid service type $type"
+ ;;
+ esac
+
+ rule_in="pipe ${ipfw_pipe_in} in ${h_in} ${rule_in} // $type $arg $slice_id"
+ rule_out="pipe ${ipfw_pipe_out} out ${h_out} ${rule_out} // $type $arg $slice_id"
+
+ # Move into the user root directory. The profile should be located there
+ ( cd /vservers/${SLICENAME}/`pwd`/ ; ${IPFW_CHECK} add ${ipfw_rule} ${rule_in} ) > /dev/null || \
+ abort "ipfw syntax error ${rule_in}"
+ ( cd /vservers/${SLICENAME}/`pwd`/ ; ${IPFW_CHECK} add ${ipfw_rule} ${rule_out} ) > /dev/null || \
+ abort "ipfw syntax error ${rule_out}"
+ fi
+
+ # check error reporting
+ ( cd /vservers/${SLICENAME}/`pwd`/ ; ${IPFW_CHECK} pipe ${ipfw_pipe_in} config ${CONFIG_PIPE_IN} ) > /dev/null || \
+ abort "ipfw syntax error pipe_in"
+ ( cd /vservers/${SLICENAME}/`pwd`/ ; ${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
+ ( cd /vservers/${SLICENAME}/`pwd`/ ; ${IPFW} pipe ${ipfw_pipe_in} config ${CONFIG_PIPE_IN} )
+ ( cd /vservers/${SLICENAME}/`pwd`/ ; ${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
+
+ # do not write on the database on test-only
+ [ "$TEST" = "1" ] && return
+ # add to the database
+ ( grep -iv -- "^${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 {CLIENT|SERVER|SERVICE} arg"
+ 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 (case insensitive)
+ grep -iv -- "^${slice_id} ${type} ${arg} " $DBFILE > ${DBFILE}.tmp
+ mv ${DBFILE}.tmp ${DBFILE}
+
+ # if there are no more 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 -iv -- "^${slice_id} BLOCK ${block_n}" $DBFILE; ) > ${DBFILE}.tmp
+ mv ${DBFILE}.tmp ${DBFILE}
+ return 0
+}
+
+#
+# Find a rule and pipe_index for the given key (xid type arg)
+# Allocate a new block if first entry for this xid.
+# Rule and pipe are not written into the database, only the block is.
+#
+# Return ipfw_rule pipe_index new_rule
+# 'new_rule' is 0 if the rule existed, 1 if it is new
+#
+# return ipfw_rule = 0 if there are no resources 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 existing block, or
+ # allocate a new one
+ local block_n=`find_block ${slice_id}`
+ [ ${block_n} = "0" ] && new_block=1 && block_n=`find_free_block`
+ [ ${block_n} = "0" -o ${block_n} -gt $BLOCK_MAX ] && echo 0 && return 0;
+
+ # We have a valid block, compute the range for user rules
+ local ipfw_rulemin=$(($IPFW_RULE_MIN + $(($M *$(($block_n - 1))))))
+ local ipfw_rulemax=$(($(($ipfw_rulemin + $M)) - 1 ))
+
+ # Find rule and pipes, reserve the last rule for the user's
+ # default rule that catches regular traffic.
+ set `allocate_resources $ipfw_rulemin $(($ipfw_rulemax - 1))`
+ ipfw_rule=$1; pipe_index=$2
+ [ $ipfw_rule = 0 ] && echo 0 && return 0 # no resources
+
+ # If this is a new block, add the slice to the lookup table
+ # and put a default rule at the end of the block.
+ 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 <slice_id type arg> with
+# the current firewall configuration. The database contains
+# slice_id type arg ipfw_rule pipe_index timeout
+# On match returns <ipfw_rule pipe_index timeout>
+# On non match returns 0 0 0
+# no echo inside
+find_rule() { # slice_id type arg
+ local ret
+ ret=`grep -i -- "^$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
+}
+
+# XXX despite the name this does not allocate but only finds holes.
+# 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
+}
+
+
+# Returns the index of a free block
+# Returns 0 if there are no resources available
+# no debug inside
+find_free_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 -iv -- "^${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] IN <pipe_conf> OUT <pipe_conf>
+# 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")
+ case x"$type" in
+ xserver|xSERVER|xclient|xCLIENT|xservice|xSERVICE)
+ do_config $SLICE_ID $timeout $type $args && return 0
+ ;;
+ esac
+ abort "'config' should be followed by {CLIENT|SERVER|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 IN pipe_conf 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
+ local p h; # port and optional hostname
+
+ [ "$1" != "IN" ] && abort "Missing addr:port, or IN requested"
+ shift
+
+ # read pipe in configuration
+ i=""
+ while [ "$1" != "" -a "$1" != "OUT" ] ; do
+ i="$i $1"
+ shift
+ done
+ CONFIG_PIPE_IN="$i" # XXX local ?
+ [ "$CONFIG_PIPE_IN" = "" ] && abort "Missing pipe in configuration"
+
+ [ "$1" != "OUT" ] && abort "Missing pipe in configuration, or missing 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"
+
+
+ # process the argument (port and hostname are separated by a @)
+ # split the argument, and prepare the remote host configuration string
+ p=`echo $arg | cut -s -d "@" -f1-` # empty it there is no separator
+ if [ "$p" = "" ] ; then
+ p=$arg
+ else
+ p=`echo $arg | cut -d "@" -f1`
+ h=`echo $arg | cut -d "@" -f2`
+ fi
+
+ # A port value is mandatory
+ [ "$p" = "" ] && abort "A port value is mandatory."
+
+ # SERVICE do not support remote hostname filtering
+ [ $type = "service" ] && [ "$h" != "" ] && \
+ abort "The service configuration do not support filtering remote hostnames."
+
+ debug "Configuration Required:"
+ debug "slice_id: $SLICE_ID"
+ debug "type: $type"
+ debug "full arg: $arg"
+ debug "mandatory port(s): $p optional hostname(s): $h"
+ debug "timeout: $timeout"
+ debug "IN: $CONFIG_PIPE_IN"
+ debug "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 {CLIENT|SERVER|SERVICE} arg [-t timeout] \
+ IN <pipe in configuration> OUT <pipe out configuration>
+ ./netconfig show {rules|pipes}
+ ./netconfig delete {CLIENT|SERVER|SERVICE} arg
+ ./netconfig refresh [-t timeout] {CLIENT|SERVER|SERVICE} arg
+
+We support three modes of operation:
+
+ CLIENT programs on the node connect to remote ports
+ and/or addresses. Emulation intercepts traffic
+ involving those ports/addresses
+
+ SERVER programs on the node listen on specific ports.
+ Emulation intercepts traffic on those ports,
+ optionally limited to specific client addresses.
+
+ SERVICE the node runs both clients and servers,
+ we can only specify the ports on which emulation
+ is configured.
+
+ 'arg' has the form PORTLIST[@ADDRLIST], where ADDRLIST is
+ optional and only supported for CLIENT and SERVER modes.
+ PORTLIST and ADDRLIST can be specified as any valid port
+ or address specifier in ipfw, e.g.
+ - a single value 443 or 10.20.30.40/24
+ - a comma-separated list 1111,2222,3333 1.2.3.4,5.6.7.8
+ - a range 1111-2222 (only for ports)
+ Addresses can also be specified as symbolic hostnames, and
+ they are resolved when the rule is installed.
+ Note that they always indicate the remote endpoint.
+
+ 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's configuration, both for the upstream and downstream link,
+follows 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:
+
+ IN|OUT delay 100ms bw 1Mbit/s plr 0.1
+
+The profile file, if present, should be located into the sliver's
+root directory.
+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
+}
+
+#--- DOCUMENTATION AND INTERNAL ARCHITECTURE ---
+#
+# When a user configures an emulated link, we need to allocate
+# two pipes and one ipfw rule number to store the parameters.
+# Reconfigurations of existing links reuse the previous resources.
+# We keep track of all resources (pipes, rules and blocks of rules)
+# in a database stored in a text file, see DATABASE FORMAT below.
+#
+# Pipes are allocated in pairs. In the database each pair is numbered
+# from PIPE_MIN to PIPE_MAX. The actual pipe numbers for each pair are
+#
+# ipfw_pipein = IPFW_PIPE_MIN + 2*(pipe_index-1)
+# ipfw_pipeout = ipfw_pipein + 1
+#
+# The rules number is allocated within a block of M consecutive rules
+# for each slice. The block is allocated at the first configuration
+# of an emulated link, and deallocated when the last link is removed.
+# In the database, blocks are numbered from BLOCK_MIN to BLOCK_MAX,
+# and the range of rules for a given block_index is
+#
+# ipfw_min_rule = RULE_BASE
+# ipfw_max_rule = RULE_BASE + ((M-1)*block_index) -1
+#
+# All lookups, and the block allocation, are done in find_allocate().
+# The rule_number and pipe_index are written in the database
+# by add_rule() after checking the correctness of the request.
+#
+#
+#--- RULESET STRUCTURE ---
+# The ruleset is made of different sections, as follows:
+# - an initial block of rules, reserved and configurable by
+# the root context only;
+# - a skipto rule (S), used to jump directly to the block
+# associated with a given slice;
+# - a second block of reserved rules, to catch remaining traffic.
+# This ends with rule number D which is an 'accept all';
+# - after D, we have a block of M rule numbers for each slice.
+# Each of these blocks ends with an 'accept all' rule;
+# - finally, rule 65535 is the firewall's 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 <block of M entries for first user>
+# RULE_BASE+M <block of M entry for second user ...>
+# ...
+#
+#--- DATABASE FORMAT ---
+# The database is stored in a text file, and contains one record per
+# line with the following structure
+#
+# XID TYPE arg1 arg2 ...
+#
+# Whitespace separates the fields. arg1, arg2, ... have different
+# meaning depending on the TYPE. XID is the slice ID.
+#
+# In the database we have the following records:
+# - one entry of type BLOCK for each slice with configured links.
+# This entry represents the block_index of the block of M ipfw
+# rules allocated to the slice, as follows:
+#
+# XID BLOCK block_index
+# (BLOCK_MIN <= block_index <= BLOCK_MAX)
+#
+# - one entry for each link (CLIENT, SERVER, SERVICE).
+# The database entry for this info has the form
+#
+# XID {CLIENT|SERVER|SERVICE} arg ipfw_rule pipe_index timeout
+#
+# 'TYPE' reflects the configuration mode;
+# 'arg' is PORTLIST@ADDRLIST and is used as a search key together
+# with the XID and TYPE;
+# 'ipfw_rule' is the unique ipfw rule number used for this
+# emulated link. It must be within the block of M rule numbers
+# allocated to the slice;
+# 'pipe_index' is the index of the pair of pipes used for the
+# configuration;
+
+#-- 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 -q and invalid chars
+debug "--- processing <${REQ}>"
+acquire_lock # critical section
+process ${REQ}
+release_lock
+debug "--- $0 END ---"
+exit 0
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+
+my $slicename=$ARGV[0];
+my $slice_dev="/vservers/$slicename/dev";
+
+my $name = <STDIN>;
+my $major = <STDIN>;
+my $minor = <STDIN>;
+chomp($name);
+chomp($major);
+chomp($minor);
+
+$name=~s/\.\.//g;
+system("mknod $slice_dev".$name."c $major $minor");
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+
+$|=1;
+
+my $slicename;
+my $xid;
+my $portnumber;
+my $fuser_cmd;
+my $pid;
+my @vinfo;
+my $foo;
+my $real_xid;
+
+$slicename = $ARGV[0];
+$xid = int(`id -u $slicename`) || die("Could not determine xid of $slicename\n");
+$portnumber = <STDIN>;
+chop($portnumber);
+
+if ($portnumber!~/^\d+$/) {
+ die("$portnumber is not a port number");
+}
+
+if ($portnumber<61001 || $portnumber>65535) {
+ die("$portnumber lies in the local port-rover range\n");
+}
+
+$fuser_cmd = "ncontext --nid $xid --migrate -- vcontext --xid $xid --migrate fuser -n tcp $portnumber 2>/dev/null";
+$pid = `$fuser_cmd` || die("Please bind to port $portnumber, e.g. run nc -l $portnumber.");
+$pid=~s/\s+//g;
+
+my $cat_cmd;
+
+$cat_cmd = "chcontext --ctx 1 cat /proc/$pid/vinfo";
+$_ = `$cat_cmd`;
+@vinfo = split /\n/;
+($#vinfo>0) || die("Port reservation failed. Please try again.\n");
+
+$_=@vinfo[0];
+
+($foo,$real_xid) = split;
+
+if (int($real_xid)!=$xid) {
+ die("Port $portnumber belongs to user $real_xid, not to you.\n");
+}
+
+# OK. We're good
+# Only, slices are allowed only 1 port reservation/session
+
+if ( -f "/dev/shm/$slicename-port" ) {
+ print "You have already reserved the following port:\n";
+ system("cat /dev/shm/$slicename-port");
+ exit(1);
+}
+
+open FIL,">/dev/shm/$slicename-port";
+print FIL "$portnumber";
+close FIL;
+
+system("iptables -t mangle -A INPUT -m tcp -p tcp --dport $portnumber -j MARK --set-mark $xid");
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+
+$|=1;
+
+my $slicename;
+my $xid;
+my $portnumber;
+my $fuser_cmd;
+my $pid;
+my @vinfo;
+my $foo;
+my $real_xid;
+
+$slicename = $ARGV[0];
+$xid = int(`id -u $slicename`) || die("Could not determine xid of $slicename\n");
+$portnumber = <STDIN>;
+chop($portnumber);
+
+if ($portnumber!~/^\d+$/) {
+ die("$portnumber is not a port number");
+}
+
+if ($portnumber<61001 || $portnumber>65535) {
+ die("$portnumber lies in the local port-rover range\n");
+}
+
+$fuser_cmd = "ncontext --nid $xid --migrate -- vcontext --xid $xid --migrate fuser -n udp $portnumber 2>/dev/null";
+$pid = `$fuser_cmd` || die("Please bind to port $portnumber, e.g. run nc -ul $portnumber.");
+$pid=~s/\s+//g;
+
+my $cat_cmd;
+
+$cat_cmd = "chcontext --ctx 1 cat /proc/$pid/vinfo";
+$_ = `$cat_cmd`;
+@vinfo = split /\n/;
+($#vinfo>0) || die("Port reservation failed. Please try again.\n");
+
+$_=@vinfo[0];
+
+($foo,$real_xid) = split;
+
+if (int($real_xid)!=$xid) {
+ die("Port $portnumber belongs to user $real_xid, not to you.\n");
+}
+
+# OK. We're good
+# Only, slices are allowed only 1 port reservation/session
+
+if ( -f "/dev/shm/$slicename-port" ) {
+ print "You have already reserved the following port:\n";
+ system("cat /dev/shm/$slicename-port");
+ exit(1);
+}
+
+open FIL,">/dev/shm/$slicename-port";
+print FIL "$portnumber";
+close FIL;
+
+system("iptables -t mangle -A INPUT -m udp -p udp --dport $portnumber -j MARK --set-mark $xid");
--- /dev/null
+#!/bin/sh
+
+DEST="/vservers/$1/home/$1/"
+
+/usr/bin/rsync -a /var/log/secure* $DEST
--- /dev/null
+#!/usr/bin/python -u
+# All vsys scripts should use STDOUT in unbuferred mode, or else sometimes your output will get bufferred and you will not see it till the buffer gets flushed.
+
+import sys
+import os
+
+vsys_config_dir = "/etc/planetlab/vsys-attributes"
+
+slicename=sys.argv[1]
+sliceid = pwd.getpwnam(slicename).pw_uid
+
+arglines = map(string.strip, sys.stdin.readlines())
+command_name = arglines[0]
+device_names = arglines[1:]
+
+print "Validating interface names... ",
+# Validate interface names
+
+for vif in device_names:
+ if len(vif)>16:
+ print "Interface name %s invalid"%(vif)
+ sys.exit(1)
+ if re.match(r'(tun|tap)%d-\d+' % sliceid, vif ) is None:
+ print "Interface name %s does not match slice id %d."%(vif, sliceid)
+ sys.exit(1)
+ print "[OK]"
+
+# The interfaces have been validated. We don't need to validate the executable
+# path for escape hatches because we are going to use execve.
+
+pid = os.fork()
+if (pid):
+ # Close open fds before execve
+ print "Closing file descriptors."
+ for fd in xrange(3, 1023):
+ try:
+ os.close(fd)
+ except OSError:
+ pass
+ # Execute command
+ vserver_command = "/usr/sbin/vserver"
+ args = [slicename]
+ args += ['exec']
+ args += [command_name]
+
+ os.system('touch /etc/vservers/%s/spaces/net'%slicename)
+
+ try:
+ os.execve(vserver_command, args)
+ except:
+ pass
+
+ os.system('rm /etc/vservers/%s/spaces/net'%slicename)
+else:
+ for vif in device_names:
+ os.system('/sbin/ip link set %s netns %d'%(vif, pid))
+
#!/bin/sh +x
-IP=/sbin/ip
-
SLICE=$1
SLICEID=`id -u $SLICE`
read INDEX
LINK=${KEY}if${INDEX}
modprobe ip_gre
-modprobe etun
### Setup EGRE tunnel
EGRE=d$LINK
-$IP tunnel add $EGRE mode gre/eth remote $REMOTE key $KEY
-$IP link set $EGRE up
+ip tunnel add $EGRE mode gre type eth remote $REMOTE key $KEY ttl 64
+ip link set $EGRE up
### Setup etun
ETUN0=a$LINK
ETUN1=b$LINK
-echo $ETUN0,$ETUN1 > /sys/module/etun/parameters/newif
+ip link add name $ETUN0 type veth peer name $ETUN1
ifconfig $ETUN0 mtu 1458 up
ifconfig $ETUN1 up
read PID
-chcontext --ctx 1 -- echo \$PID > /sys/class/net/$ETUN0/new_ns_pid
+ip link set $ETUN0 netns \$PID
EOF
chmod +x $GRAB
iptables -t mangle -D FORWARD -o $BRIDGE -j MARK --set-mark $SLICEID
# Get rid of etun devices, only need name of one of them
-echo $ETUN1 > /sys/module/etun/parameters/delif
+ip link delete dev $ETUN1
# Get rid of bridge
ifconfig $BRIDGE down
#!/bin/sh +x
-IP=/sbin/ip
-
SLICE=$1
SLICEID=`id -u $SLICE`
read KEY
-modprobe etun
-
### Setup etun
ETUN0=nat$KEY
ETUN1=natx$KEY
-echo $ETUN0,$ETUN1 > /sys/module/etun/parameters/newif
-ifconfig $ETUN1 10.0.$KEY.1 up
+ip link add name $ETUN0 type veth peer name $ETUN1
+ifconfig $ETUN1 10.0.$KEY.1/24 up
-/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
-/sbin/iptables -A FORWARD -i eth0 -o $ETUN1 -m state --state RELATED,ESTABLISHED -j ACCEPT
-/sbin/iptables -A FORWARD -i $ETUN1 -o eth0 -j ACCEPT
+iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
+iptables -A FORWARD -i eth0 -o $ETUN1 -m state --state RELATED,ESTABLISHED -j ACCEPT
+iptables -A FORWARD -i $ETUN1 -o eth0 -j ACCEPT
### Create "grab link" script
GRAB=/vsys/local_grab-$ETUN0
read PID
-chcontext --ctx 1 -- echo \$PID > /sys/class/net/$ETUN0/new_ns_pid
+ip link set $ETUN0 netns \$PID
EOF
chmod +x $GRAB
read NULL
# Remove iptables rules
-/sbin/iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
-/sbin/iptables -D FORWARD -i eth0 -o $ETUN1 -m state --state RELATED,ESTABLISHED -j ACCEPT
-/sbin/iptables -D FORWARD -i $ETUN1 -o eth0 -j ACCEPT
+iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
+iptables -D FORWARD -i eth0 -o $ETUN1 -m state --state RELATED,ESTABLISHED -j ACCEPT
+iptables -D FORWARD -i $ETUN1 -o eth0 -j ACCEPT
# Get rid of etun devices, only need name of one of them
-echo $ETUN1 > /sys/module/etun/parameters/delif
+ip link delete dev $ETUN1
# Clean up files
rm -f $GRAB $GRAB.acl
--- /dev/null
+#!/bin/bash
+#
+# Giovanni Di Stasi
+# Copyright (C) 2009 UniNa
+# $Id$
+#
+# This is a backend script to be used with
+# the vsys system. It allows to define and
+# manage slice-specific routing tables.
+# The routing rules added to these routing
+# tables affect only the respective slices.
+#
+# This script is meant to be called from a
+# frontend script in the slice environment.
+#
+# Fronted usage:
+# sliceip enable <interface>
+# This is the first command to issue; it enables the use
+# of the interface for the slice. This command has to be issued
+# for each interface involved in the slice-specific routing rules.
+#
+# sliceip disable <interface>
+# This is to disable the use of the interface for the slice.
+#
+# sliceip route show
+# This command shows the current routing rules of the
+# slice-specific routing table
+#
+# sliceip route add to <destination> via <gateway> dev <interface>
+# This command adds a rule to reach <destination> through the host
+# <gateway> that can be reached on the interface <interface>
+# ...
+#
+# sliceip in general supports all the commands of the "ip" command of
+# the "iproute2" suite. Refer to ip manpage for further information.
+#
+# Some examples:
+# sliceip route add to 143.225.229.142 via 192.168.8.2 dev ath0
+# sliceip route add default via 10.1.1.1 dev ath0
+#
+# If you want to test the script from the root context you need
+# to call it as vsys would do:
+# sliceip <slice_name>
+# Then you can issue to its standard input the commands previously explained
+# (but you have to remove the initial "sliceip"). Ex.:
+# route add to 143.225.229.142 via 192.168.8.2 dev ath0
+
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+# sliver wich called the script
+sliver=$1
+
+#files used
+RT_TABLES="/etc/iproute2/rt_tables"
+INT_FILE="/tmp/slcroute_ifns"
+
+# routing tables from 100 to 255 are used
+FIRST_TABLE=100
+
+DEBUG=0
+
+#this script can also work on a Linux machine, in wich case
+#it enables user-specific routing tables
+LINUX_ENV=0 # 0 - Linux host;
+ # does not work for the icmp protocol
+
+PLANET_ENV=1 # 1 - PlanetLab context (slice-specific routing)
+
+#select the PlanetLab environment
+ENVIRONMENT=$PLANET_ENV
+
+
+# enable an interface for the slice specific routing rules
+# and initialise the slice routing table
+function enable_interface(){ # $1 calling sliver; $2 interface to enable
+ local sliver=$1
+ local interface="$2"
+ local ip=`get_address $interface`
+
+ if [[ "" == $ip ]]; then
+ echo "Failed in getting address of $interface"
+ return 1
+ fi
+
+ #create the sliceip netfilter chains
+ check_chains
+
+ local nid=`get_nid $sliver`
+ local num_active=`get_num_activated $sliver`
+
+ if ! is_active $sliver $interface; then
+ if [[ $num_active == 0 ]]; then
+ #define the routing table for the slice and set some iptables rules in order to mark user's packets;
+ create_table $sliver
+ fi
+
+ #Adds an SNAT rule to set the source IP address of packets that are about to go out through $interface.
+ #The kernel sets the source address of packets when the first routing process happens (following the rules
+ #of the main routing table); when the rerouting process happens (following the user/slice specific rules)
+ #the source address is not modified. Consequently, we need to add this rule to change the source ip address
+ #to the $interface source address.
+ exec "iptables -t nat -A $NAT_POSTROUTING -o $interface -j SNAT --to-source $ip -m mark --mark $nid"
+
+ set_active $sliver $interface $ip
+ else
+ local old_ip=`get_ip_from_file $sliver $interface`
+
+ #if the ip of the interface has changed, set the new SNAT rule
+ if [[ $old_ip != $ip ]]; then
+ #remove the rule for the old ip
+ exec "iptables -t nat -D $NAT_POSTROUTING -o $interface -j SNAT --to-source $old_ip -m mark --mark $nid"
+ #insert the new rule
+ exec "iptables -t nat -A $NAT_POSTROUTING -o $interface -j SNAT --to-source $ip -m mark --mark $nid"
+ set_deactivated $sliver $interface $old_ip
+ set_active $sliver $interface $ip
+ fi
+
+
+ fi
+
+}
+
+# disable the interface for the slice-specific routing rules
+function disable_interface(){
+ local sliver=$1
+ local interface=$2
+ local ip=`get_ip_from_file $sliver $interface`
+ local nid=`get_nid $sliver`
+
+ if is_active $sliver $interface >/dev/null 2>&1; then
+ exec "iptables -t nat -D $NAT_POSTROUTING -o $interface -j SNAT --to-source $ip -m mark --mark $nid"
+
+ local num_ifn_on=`get_num_activated $sliver`
+
+ if [[ $num_ifn_on == 1 ]]; then
+ delete_table $sliver
+ fi
+ set_deactivated $sliver $interface
+ fi
+
+}
+
+# wrapper function used to execute system commands
+function exec(){
+ local command=$1
+
+ if ! [[ $command ]]; then
+ echo "Error in exec. No argument."
+ exit 1
+ else
+ if ! $command; then
+ if [[ $DEBUG == 1 ]]; then echo "Error executing \"$1\""; fi
+ exit 1
+ fi
+ fi
+
+}
+
+# decides wich id to use for the slice-specific routing table
+function get_table_id(){
+ local sliver=$1
+ k=$FIRST_TABLE
+
+ while [[ $k < 255 ]] && grep $k $RT_TABLES >/dev/null 2>&1 ; do
+ k=$((k+1))
+ done
+
+ if [[ $k == 255 ]]; then
+ logm "No routing tables available. Exiting."
+ return 1
+ fi
+
+ echo $k
+}
+
+
+# create the slice-specifig routing table
+function create_table(){
+ local sliver=$1
+ local table_name=`get_table_name $sliver`
+ local table_id=`get_table_id $sliver`
+ local temp_nid=`get_temp_nid $sliver`
+
+ if ! grep $table_name $RT_TABLES > /dev/null 2>&1; then
+ echo "$table_id $table_name" >> $RT_TABLES
+ else
+ echo "WARNING: $table_name routing table already defined."
+ fi
+
+ set_routes $sliver $table_name
+
+ return 0
+}
+
+# delete the slice-specific routing table
+function delete_table(){
+ local sliver=$1
+ local table_name=`get_table_name $sliver`
+ local table_id=`get_nid $sliver`
+ local temp_nid=`get_temp_nid $sliver`
+
+ if ! grep $table_name $RT_TABLES > /dev/null 2>&1; then
+ return 1
+ else
+ exec "ip route flush table $table_name" >/dev/null 2>&1
+ unset_routes $sliver $table_name
+ remove_line "$RT_TABLES" "$table_name"
+ fi
+
+ return 0
+}
+
+# remove a line from a file
+function remove_line(){
+ local filename=$1
+ local regex=$2
+
+ #remove interface line from the file
+ exec "sed -i /${regex}/d $filename"
+}
+
+# get the slice-specific routing table name
+function get_table_name(){
+ local sliver=$1;
+ echo "${sliver}_slcip"
+}
+
+#remove files used by sliceip and the added routing tables
+function clean_iproute_conf(){
+ while grep "slcip" $RT_TABLES >/dev/null 2>&1; do
+ remove_line $RT_TABLES "slcip"
+ done
+
+ rm -f ${INT_FILE}-*
+
+}
+
+#get slice network id
+function get_nid(){
+ id -u ${1}
+}
+
+# set the firewall rules. Mainly, it asks VNET+ to set the netfilter mark of packets belonging to the slice to the slice-id
+# and then associates those packets with the routing table allocated for that slice.
+function set_routes(){
+ local sliver=$1
+ local table_name=$2
+ local sliver_nid=`get_nid $sliver`
+ local temp_nid=`get_temp_nid $sliver`
+
+ if [ $ENVIRONMENT == $PLANET_ENV ]; then
+ #Linux kernel triggers a rerouting process, wich is needed to perfom slice-specific routing,
+ #if it sees that the netfilter mark has been altered in the iptables mangle chain.
+ #As VNET+ sets the netfilter mark of some packets in advance (to the slice-id value) before they enter the iptables mangle chain,
+ #we need to change it here (otherwise the rerouting process is not triggered for them).
+ exec "iptables -t mangle -I $MANGLE_OUTPUT 1 -m mark --mark $sliver_nid -j MARK --set-mark $temp_nid"
+
+ #make sure the netfilter mark of those "strange packets" won't be changed by the following rule
+ exec "iptables -t mangle -I $MANGLE_OUTPUT 2 -m mark --mark $temp_nid -j RETURN"
+
+ #Here we ask VNET+ to set the netfilter mark for the remaining packets (to the slice-id)
+ #we need to call this only once
+ if [[ $first_time == 1 ]]; then
+ exec "iptables -t mangle -A $MANGLE_OUTPUT -j MARK --copy-xid 0x00"
+ fi
+
+ elif [ $ENVIRONMENT == $LINUX_ENV ]; then
+ #the same in the case of a "plain" Linux box. In this case we do not use VNET+ but
+ #the owner module of iptables.
+ exec "iptables -t mangle -A $MANGLE_OUTPUT -m owner --uid-owner $sliver_nid -j MARK --set-mark $sliver_nid"
+ fi
+
+ if [ $ENVIRONMENT == $PLANET_ENV ]; then
+ #Here the netfilter mark is restored to the slice-id value for the "strange packets"
+ exec "iptables -t mangle -A $MANGLE_POSTROUTING -m mark --mark $temp_nid -j MARK --set-mark $sliver_nid"
+ fi
+
+ #Set the routing for the slice to be applied following the rules in $table_name"
+ #for the slice packets...
+ exec "ip rule add fwmark $sliver_nid table $table_name"
+ #...and for the "strange packets"
+ exec "ip rule add fwmark $temp_nid table $table_name"
+
+ exec "ip route flush cache" >/dev/null 2>&1
+}
+
+
+# remove the firewall rules.
+function unset_routes(){
+ local sliver=$1
+ local table_name=$2
+ local sliver_nid=`get_nid $sliver`
+ local temp_nid=`get_temp_nid $sliver`
+
+ if [ $ENVIRONMENT == $PLANET_ENV ]; then
+ #removes the rules for the netfilter marks (for the "strange packets")
+ exec "iptables -t mangle -D $MANGLE_OUTPUT -m mark --mark $sliver_nid -j MARK --set-mark $temp_nid"
+ exec "iptables -t mangle -D $MANGLE_OUTPUT -m mark --mark $temp_nid -j RETURN"
+
+ #removes the rule for restoring the original mark
+ exec "iptables -t mangle -D $MANGLE_POSTROUTING -m mark --mark $temp_nid -j MARK --set-mark $sliver_nid"
+
+ elif [ $ENVIRONMENT == $LINUX_ENV ]; then
+ #removes the rules that asks the owner module of iptables to set the netfilter mark to the user-id
+ exec "iptables -t mangle -D $MANGLE_OUTPUT -m owner --uid-owner $sliver_nid -j MARK --set-mark $sliver_nid"
+ fi
+
+ exec "ip rule del fwmark $temp_nid table $table_name"
+ exec "ip rule del fwmark $sliver_nid table $table_name"
+
+ exec "ip route flush cache"
+
+}
+
+# additional iptables chains where sliceip inserts its rules
+NAT_POSTROUTING="sliceip"
+MANGLE_OUTPUT="sliceip_output"
+MANGLE_POSTROUTING="sliceip_postrouting"
+
+# create the chains
+check_chains(){
+ first_time=0
+
+ #create the chain where SNAT is performed
+ if iptables -t nat -N $NAT_POSTROUTING >/dev/null 2>&1; then
+ #it's the first time sliceip is called, the chain was not defined
+ first_time=1
+
+ #create a chain where the netfilter mark is set
+ exec "iptables -t mangle -N $MANGLE_OUTPUT"
+
+ #create a chain where the netfilter mark for some packets is restored (see set_routes)
+ exec "iptables -t mangle -N $MANGLE_POSTROUTING"
+
+ #add the rules to take packets to the previously defined chains
+ exec "iptables -t nat -A POSTROUTING -j $NAT_POSTROUTING"
+ exec "iptables -t mangle -A OUTPUT -j $MANGLE_OUTPUT"
+ exec "iptables -t mangle -I POSTROUTING 1 -j $MANGLE_POSTROUTING"
+
+ #cleaning up
+ clean_iproute_conf
+ fi
+}
+
+# get the ip address of an interface
+function get_address(){
+ local interface=$1
+ local ip=""
+
+ ip=`ifconfig $interface | grep inet\ addr | cut -d ":" -f 2 | cut -d " " -f 1`;
+
+ if valid_dotted_quad $ip; then
+ echo $ip;
+ else
+ echo "";
+ fi
+
+}
+
+# get the temporary mark to be applied to the packets of the slice
+function get_temp_nid(){
+ local sliver_nid=`get_nid $1`
+ local temp_nid=$((0x20000+$sliver_nid))
+ echo $temp_nid
+}
+
+# log function
+function logm(){
+ logger $1
+}
+
+# get the name of the filename in wich we store information about
+# the interfaces in use by the user
+function get_filename_sliver(){
+ local sliver=$1
+ echo "${INT_FILE}-$sliver"
+}
+
+function set_active(){
+ local sliver=$1
+ local interface=$2
+ local ip=$3
+ local filename="${INT_FILE}-$sliver"
+ echo "$interface $ip" >> $filename
+}
+
+function set_deactivated(){
+ local sliver=$1
+ local interface=$2
+ local filename=`get_filename_sliver $sliver`
+ remove_line $filename $interface
+}
+
+function is_active(){
+ local sliver=$1
+ local interface=$2
+ local filename=`get_filename_sliver $sliver`
+
+ if grep $interface $filename >/dev/null 2>&1; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function get_num_activated(){
+ local sliver=$1
+ local filename=`get_filename_sliver $sliver`
+
+ if ! [ -e $filename ]; then
+ echo 0;
+ else
+ wc -l $filename | cut -f 1 -d " ";
+ fi
+}
+
+
+function get_ip_from_file(){
+ local sliver=$1
+ local interface=$2
+
+ local filename=`get_filename_sliver $sliver`
+
+ cat $filename | grep $interface | cut -d " " -f 2
+}
+
+
+# check ip addresses
+function valid_dotted_quad(){
+ oldIFS=$IFS
+ IFS=.
+ set -f
+ set -- $1
+ if [ $# -eq 4 ]
+ then
+ for seg
+ do
+ case $seg in
+ ""|*[!0-9]*) return 1; break ;; ## Segment empty or non-numeric char
+ *) [ $seg -gt 255 ] && return 2 ;;
+ esac
+ done
+ else
+ return 3 ## Not 4 segments
+ fi
+ IFS=$oldIFS
+ set +f
+ return 0;
+}
+
+
+# BEGIN
+# the script starts here
+
+if [[ $sliver == "" ]]; then
+ echo "I need the first argument (the sliver name)";
+ exit 1
+fi
+
+# read a line from the vsys pipe
+read line
+
+# separate the first word of the line from the others
+command=`echo ${line%% *}`
+rest=`echo ${line#* }`
+
+case "$command" in
+ enable)
+ logger "sliceip command received from $sliver: $line"
+ enable_interface $sliver "$rest"
+ ;;
+
+ disable)
+ logger "sliceip command received from $sliver: $line"
+ disable_interface $sliver "$rest"
+ ;;
+
+ *)
+ logger "sliceip command received from $sliver: $line"
+ table_sliver=`get_table_name $sliver`
+
+ if ! grep "$table_sliver" $RT_TABLES >/dev/null 2>&1; then
+ echo "Error. The slice routing table is not defined. Execute sliceip enable <interface>."
+ exit 1
+ else
+ #add the routing rule - ip is called with the same parameters of sliceip but the indication of
+ #the table in wich the rule is to be inserted is appended
+ exec "ip $line table $table_sliver"
+ fi
+ ;;
+
+esac
+
+exit 0
+
+
+
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+
+my $slicename=$ARGV[0];
+my $slice_dir="/vservers/$slicename/";
+my $localpath = <STDIN>;
+
+chomp($localpath);
+
+$localpath=$slice_dir.$localpath;
+
+my $pathtest;
+
+$pathtest='';
+while ($localpath=~/(\/?[\w\d\-_]+\/?)/g) {
+ $pathtest=$pathtest.$1;
+}
+
+if ($pathtest ne $localpath) {
+ die "$localpath is not a safe path";
+}
+
+my $mntcmd="/bin/umount $localpath";
+system($mntcmd);
+
+if ($?) {
+ print "Mount failed: $?";
+}
--- /dev/null
+#!/usr/bin/python
+# VSYS script to ifdown per-slice virtual network interfaces from the root slice
+# Thom Haddow - 06/10/09
+#
+# Gets slice name as argv[1]
+# Takes remaining args on stdin:
+# - Interface name (eg [tun|tap]<sliceid>-<n>)
+
+import sys
+import pwd
+import os
+import re
+
+
+if len(sys.argv) != 2: sys.exit(1)
+
+# VSYS scripts get slicename as $1
+slicename=sys.argv[1]
+sliceid = pwd.getpwnam(slicename).pw_uid
+
+
+# Read interface name
+vif = sys.stdin.readline().strip() # interface name
+
+
+# Validate interface name
+if len(vif)>16:
+ print >>sys.stderr, "Interface name %s invalid"%(vif)
+ sys.exit(1)
+
+if re.match(r'(tun|tap)%d-\d+' % sliceid, vif ) is None:
+ print >>sys.stderr, "Interface name %s does not match slice id %d."%(vif, sliceid)
+ sys.exit(1)
+
+
+
+# Bring interface down
+
+cmd_ifconfig = "/sbin/ifconfig %s down" % (vif)
+os.system(cmd_ifconfig)
+
+# Remove iptables rules
+cmd_iptables_del_in = "/sbin/iptables -D INPUT -i %s -m mark ! --mark %d -j DROP 2>/dev/null" % (vif, sliceid)
+cmd_iptables_del_out = "/sbin/iptables -D OUTPUT -o %s -m mark ! --mark %d -j DROP 2>/dev/null" % (vif, sliceid)
+
+os.system(cmd_iptables_del_in)
+os.system(cmd_iptables_del_out)
--- /dev/null
+#!/usr/bin/python
+# VSYS script to configure per-slice virtual network interfaces from the root slice
+# Thom Haddow - 06/10/09
+#
+# Gets slice name as argv[1]
+# Takes remaining args on stdin:
+# - Interface name (eg [tun|tap]<sliceid>-<n>)
+# - IP address (eg 1.2.3.4)
+# - Netmask (as int, e.g. 24)
+# - Followed by options as name=value pairs
+
+import sys
+import pwd
+import re
+import socket
+import struct
+import os
+import string
+
+vsys_config_dir = "/etc/planetlab/vsys-attributes"
+
+if len(sys.argv) != 2: sys.exit(1)
+
+# VSYS scripts get slicename as $1
+slicename=sys.argv[1]
+sliceid = pwd.getpwnam(slicename).pw_uid
+
+netblock_config=os.path.join(vsys_config_dir,slicename,"vsys_vnet")
+
+# Read netblock allocation file
+base = None
+
+for netblock in open(netblock_config,'r'):
+ base, mask = netblock.split('/')
+
+if base is None:
+ print >>sys.stderr, "Could not find entry for slice %s in netblock config file %s" % (slicename, netblock_config)
+ sys.exit(1)
+
+
+### Read args from stdin
+arglines = map(string.strip, sys.stdin.readlines())
+
+if len(arglines)<3:
+ print >>sys.stderr, "Insufficient argument lines."
+ sys.exit(1)
+
+vif = arglines[0] # interface name
+vip = arglines[1] # IP
+vmask = int(arglines[2]) # netmask as int
+
+# Create options list
+if len(arglines)>3:
+ options = arglines[3:]
+else:
+ options = []
+
+# Convert network base addr to int format by unpacking as 32bit net-ordered long (!L)
+base_int = struct.unpack('!L',socket.inet_aton(base))[0]
+mask = int(mask)
+
+
+### Validate args
+# Validate interface name
+if len(vif)>16:
+ print >>sys.stderr, "Interface name %s invalid"%(vif)
+ sys.exit(1)
+
+if re.match(r'(tun|tap)%d-\d+' % sliceid, vif ) is None:
+ print >>sys.stderr, "Interface name %s does not match slice id %d."%(vif, sliceid)
+ sys.exit(1)
+
+
+
+# Validate requested IP and convert to int format.
+try:
+ vip_int = struct.unpack('!L',socket.inet_aton(vip))[0]
+except socket.error:
+ print >>sys.stderr, "Invalid IP: %s" % vip
+ sys.exit(1)
+
+# Check IP is in netblock
+if (vip_int>>(32-mask)) != (base_int>>(32-mask)):
+ print >>sys.stderr, "Requested IP %s not in netblock %s/%d" % (vip,base,mask)
+ sys.exit(1)
+
+# TODO. Check IP is not in use?
+
+# Validate mask: Check requested mask is sane and within our netblock
+if vmask>32 or vmask <8:
+ print >>sys.stderr, "Requested netmask /%d is invalid" %(vmask)
+ sys.exit(1)
+
+if vmask<mask:
+ print >>sys.stderr, "Requested netmask /%d larger than allocation /%d" %(vmask, mask)
+ sys.exit(1)
+
+
+
+### Process options
+
+opt_txqueuelen = None
+opt_rp_filter = None
+
+
+for optionline in options:
+ if len(optionline)==0: continue
+ try:
+ opt, val = optionline.split('=')
+ except:
+ print >>sys.stderr, "Bad option line: \"%s\"" % (optionline)
+ sys.exit(1)
+
+ if opt=="rp_filter":
+ if val=="0":
+ opt_rp_filter="0"
+ elif val=="1":
+ opt_rp_filter="1"
+ else:
+ print >>sys.stderr, "rp_filter value invalid: \"%s\"" % (val)
+ sys.exit(1)
+
+ elif opt=="txqueuelen":
+ intval = int(val)
+ if intval<1 or intval>10000:
+ print >>sys.stderr, "txqueuelen value %s out of range 1-10000" % (val)
+ sys.exit(1)
+ opt_txqueuelen = intval
+
+ else:
+ print >>sys.stderr, "Unknown option: \"%s\"" % (opt)
+ sys.exit(1)
+
+
+
+### Configure interface
+
+if opt_txqueuelen is None:
+ cmd_ifconfig = "/sbin/ifconfig %s %s/%d" % (vif, vip, vmask)
+else:
+ cmd_ifconfig = "/sbin/ifconfig %s %s/%d txqueuelen %d" % (vif, vip, vmask, opt_txqueuelen)
+
+os.system(cmd_ifconfig)
+
+# Add iptables rules (Clearing old ones first, if they exist)
+cmd_iptables_in = "/sbin/iptables -A INPUT -i %s -m mark -m state --state NEW ! --mark %d -j DROP" % (vif, sliceid)
+cmd_iptables_del_in = "/sbin/iptables -D INPUT -i %s -m mark -m state --state NEW ! --mark %d -j DROP 2>/dev/null" % (vif, sliceid)
+cmd_iptables_out = "/sbin/iptables -A OUTPUT -o %s -m state --state NEW -m mark ! --mark %d -j DROP" % (vif, sliceid)
+cmd_iptables_del_out = "/sbin/iptables -D OUTPUT -o %s -m state --state NEW -m mark ! --mark %d -j DROP 2>/dev/null" % (vif, sliceid)
+
+os.system(cmd_iptables_del_in)
+os.system(cmd_iptables_in)
+os.system(cmd_iptables_del_out)
+os.system(cmd_iptables_out)
+
+# Process additional options
+if opt_rp_filter is not None:
+ rp_cmd = "/sbin/sysctl net.ipv4.conf.%s.rp_filter=%s" % (vif, opt_rp_filter)
+ os.system(rp_cmd)
--- /dev/null
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "fdpass.h"
+
+#define MAX_BUFSIZE (32*1024*1024)
+
+/*------------------------------------------------------------------*/
+void
+receive_argument(int control_fd, int *rcvbuf, int *sndbuf)
+{
+ if (recv(control_fd, rcvbuf, sizeof(int), 0) != sizeof(int)) {
+ fprintf(stderr, "receiving the first argument failed\n");
+ exit(-1);
+ }
+ if (recv(control_fd, sndbuf, sizeof(int), 0) != sizeof(int)) {
+ fprintf(stderr, "receiving the first argument failed\n");
+ exit(-1);
+ }
+}
+/*------------------------------------------------------------------*/
+int
+main(int argc, char *argv[])
+{
+ int control_channel_fd, magic_socket;
+ int rcvbufsize = 0, sndbufsize = 0;
+
+ if (argc < 3) {
+ printf("This script is called by vsys.\n");
+ exit(1);
+ }
+
+ sscanf(argv[2],"%d", &control_channel_fd);
+
+ /* receive paramaters: rcvbufsize and sndbufsize */
+ receive_argument(control_channel_fd, &rcvbufsize, &sndbufsize);
+ if (rcvbufsize > MAX_BUFSIZE)
+ rcvbufsize = MAX_BUFSIZE;
+ if (sndbufsize > MAX_BUFSIZE)
+ sndbufsize = MAX_BUFSIZE;
+
+ magic_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if (magic_socket == -1) {
+ fprintf(stderr, "Error creating socket: %d\n", errno);
+ exit(1);
+ }
+
+ /* buffer size <= 0 means we should ignore the parameter */
+ if (rcvbufsize > 0) {
+ if (setsockopt(magic_socket,
+ SOL_SOCKET,
+ SO_RCVBUFFORCE,
+ &rcvbufsize, sizeof(unsigned int))) {
+ fprintf(stderr, "Error calling setsockopt for RCVBUFFORCE: %d\n",
+ errno);
+ exit(1);
+ }
+ }
+ if (sndbufsize > 0) {
+ if (setsockopt(magic_socket,
+ SOL_SOCKET,
+ SO_SNDBUFFORCE,
+ &sndbufsize, sizeof(unsigned int))) {
+ fprintf(stderr, "Error calling setsockopt for SNDBUFFORCE: %d\n",
+ errno);
+ exit(1);
+ }
+ }
+
+ send_fd(control_channel_fd, magic_socket);
+}
--- /dev/null
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "fdpass.h"
+
+unsigned int rcvbuf = 16*1024*1024;
+unsigned int arg_length = 128;
+unsigned int mountflags = MS_NODEV | MS_NOSUID;
+
+FILE *logfd;
+
+void receive_argument(int control_channel_fd, char *source) {
+ int received;
+ received=recv(control_channel_fd, source, arg_length, 0);
+ if (received<arg_length) {
+ fprintf(logfd,"Error receiving arguments over the control buffer\n");
+ close(logfd);
+ exit(1);
+ }
+}
+
+int set_magic_fd (char *data, int new_fd) {
+ char *ptr;
+ int fd;
+
+ data[arg_length-1]='\0';
+ ptr = strstr(data,"fd=");
+ if (!ptr)
+ return -1;
+
+ // Found two fd= expressions
+ if (strstr(ptr+3,"fd="))
+ return -1;
+
+ if (*(ptr+3)!='\0') {
+ char *new_data = (char *) malloc(arg_length);
+ char *head = (char *) malloc(arg_length);
+ char *tail;
+ sscanf(ptr+3,"%d",&fd);
+ strncpy(head, data, ptr - data);
+ tail = strchr(ptr+3,',');
+ sprintf(new_data,"%sfd=%d%s",head,new_fd,tail);
+ strcpy(data,new_data);
+ free(head);
+ free(new_data);
+ return fd;
+ }
+ else
+ return -1;
+}
+
+void check_source(char *source) {
+ source[arg_length-1]='\0';
+ if (strchr(source,'/') || strstr(source,"..")) {
+ fprintf(logfd, "Tried mounting with source = %s\n", source);
+ close(logfd);
+ exit(1);
+ }
+}
+
+void check_target(char *target) {
+ target[arg_length-1]='\0';
+ if (strstr(target,"..")) {
+ fprintf(logfd,"Tried mounting with target = %s\n", target);
+ close(logfd);
+ exit(1);
+ }
+}
+
+void check_fstype(char *filesystemtype) {
+ if (strncmp(filesystemtype,"fuse",4)) {
+ fprintf(logfd,"Tried mounting filesystem type %s\n", filesystemtype);
+ close(logfd);
+ exit(1);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ int control_channel_fd, magic_fd, mount_fd;
+ char source[128],target[128],filesystemtype[128],data[128],slice_target[1024];
+
+ int received;
+
+ if (argc < 3) {
+ printf("This script is called by vsys.\n");
+ exit(1);
+ }
+
+ char *slice_name = argv[1];
+
+ logfd=fopen("/tmp/fuselog","w");
+ if (!logfd) {logfd = stderr;}
+
+ sscanf(argv[2],"%d", &control_channel_fd);
+
+ if (control_channel_fd <3 || control_channel_fd > 1023) {
+ printf ("Got control_channel_fd = %d\n", control_channel_fd);
+ exit(1);
+ }
+
+ receive_argument(control_channel_fd, source);
+ receive_argument(control_channel_fd, target);
+ receive_argument(control_channel_fd, filesystemtype);
+ receive_argument(control_channel_fd, data);
+
+ mount_fd = receive_fd (control_channel_fd);
+
+ if (mount_fd < 2) {
+ printf("mount_fd = %d\n", mount_fd);
+ exit(1);
+ }
+
+ set_magic_fd(data, mount_fd);
+
+
+ check_source(source);
+ check_target(target);
+ check_fstype(filesystemtype);
+
+ sprintf(slice_target,"/vservers/%s/%s", slice_name, target);
+
+ fprintf(logfd, "Mount fd: %d Source: %s slice_target: %s fstype: %s mountflags: %d data: %s\n", mount_fd, source, slice_target, filesystemtype, mountflags, data);
+
+ if (!mount(source, slice_target, filesystemtype, mountflags, data)) {
+ send_fd(control_channel_fd, mount_fd);
+ }
+ else {
+ printf ("Error executing mount\n");
+ exit(1);
+ }
+
+ close(logfd);
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#include "fdpass.h"
+
+/*
+ * Definitions for IP type of service
+ */
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IPTOS_MINCOST 0x02
+#define IPTOS_NORMALSVC 0x00
+
+static void receive_argument(int control_fd, int *TOS_value)
+{
+ if (recv(control_fd, TOS_value, sizeof(int), 0) != sizeof(int)) {
+ fprintf(stderr, "receiving the IP_TOS argument failed\n");
+ exit(-1);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int control_channel_fd, magic_socket;
+ int TOS_value = IPTOS_NORMALSVC;
+
+ if (argc < 3) {
+ printf("This script is called by vsys.\n");
+ exit(1);
+ }
+
+ control_channel_fd = atoi(argv[2]);
+
+ /* receive IP_TOS paramater */
+ receive_argument(control_channel_fd, &TOS_value);
+
+ switch (TOS_value)
+ {
+ case IPTOS_NORMALSVC:
+ case IPTOS_MINCOST:
+ case IPTOS_RELIABILITY:
+ case IPTOS_THROUGHPUT:
+ case IPTOS_LOWDELAY:
+ break;
+ default:
+ fprintf(stderr, "IP_TOS value not known: %d\n", errno);
+ exit(1);
+ }
+
+ magic_socket = receive_fd(control_channel_fd);
+ if (magic_socket == -1) {
+ fprintf(stderr, "Error creating socket: %d\n", errno);
+ exit(1);
+ }
+
+ if (setsockopt(magic_socket, IPPROTO_IP, IP_TOS, &TOS_value, sizeof(TOS_value)) < 0 ) {
+ fprintf(stderr, "Error calling setsockopt for IPPROTO_IP: %d\n", errno);
+ exit(1);
+ }
+
+ send_fd(control_channel_fd, magic_socket);
+}
--- /dev/null
+/* fd_tuntap.c: VSYS script to allocate slice-local tuntap interfaces.
+ * Thom Haddow - 06/09/09
+ *
+ * Reads interface type from local control unix socket, replies with fd for new
+ * (unconfigured) tuntap interface. VSYS client can get interface name with
+ * TUNGETIFF ioctl.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+int send_vif_fd(int sock_fd, int vif_fd, char *vif_name)
+{
+ int retval;
+ struct msghdr msg;
+ struct cmsghdr *p_cmsg;
+ struct iovec vec;
+ size_t cmsgbuf[CMSG_SPACE(sizeof(vif_fd)) / sizeof(size_t)];
+ int *p_fds;
+
+
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
+ p_cmsg = CMSG_FIRSTHDR(&msg);
+ p_cmsg->cmsg_level = SOL_SOCKET;
+ p_cmsg->cmsg_type = SCM_RIGHTS;
+ p_cmsg->cmsg_len = CMSG_LEN(sizeof(vif_fd));
+ p_fds = (int *) CMSG_DATA(p_cmsg);
+ *p_fds = vif_fd;
+ msg.msg_controllen = p_cmsg->cmsg_len;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+
+ /* Send the interface name as the iov */
+ vec.iov_base = vif_name;
+ vec.iov_len = strlen(vif_name)+1;
+
+ while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
+ if (retval != 1) {
+ perror("sending file descriptor");
+ return -1;
+ }
+ return 0;
+}
+
+
+
+int main(int argc, char *argv[])
+{
+ int control_channel_fd;
+ int tap_fd;
+ int slice_uid;
+ char if_name[IFNAMSIZ];
+ int if_type;
+ struct ifreq ifr;
+ struct passwd *pwd;
+
+ if(argc < 3) {
+ printf("This script is called by vsys.\n");
+ exit(-1);
+ }
+
+
+ /* Get slice UID and control channel fd from VSYS args */
+ pwd = getpwnam(argv[1]);
+ if(pwd==NULL) {
+ perror("Failed to lookup UID");
+ exit(-1);
+ }
+ slice_uid = pwd->pw_uid;
+ sscanf(argv[2],"%d", &control_channel_fd);
+
+
+
+ /* Get type param from control channel. */
+ if(recv(control_channel_fd, &if_type, sizeof(int), 0) != sizeof(int)) {
+ perror("fd_tuntap: Failed to read from control channel");
+ exit(-1);
+ }
+
+
+ /* Generate basename for interface */
+ if(if_type==IFF_TUN) {
+ sprintf(if_name, "tun%d-%%d", slice_uid);
+ }
+ else if(if_type==IFF_TAP) {
+ sprintf(if_name, "tap%d-%%d", slice_uid);
+ }
+ else { /* TODO: Might also want to allow the other types? */
+ fprintf(stderr, "fd_tuntap: %d is not a valid interface type",if_type);
+ exit(-1);
+ }
+
+ /* Open tun device */
+ if( (tap_fd = open("/dev/net/tun", O_RDWR)) < 0 ) {
+ system("modprobe tun");
+ if( (tap_fd = open("/dev/net/tun", O_RDWR)) < 0 ) {
+ perror("ERROR: tun_alloc():open(/dev/net/tun)");
+ exit(-1);
+ }
+ }
+
+
+ /* Set interface type */
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = if_type;
+ strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+ if( ioctl(tap_fd, TUNSETIFF, (void *) &ifr) < 0 ) {
+ close(tap_fd);
+ perror("fd_tuntap: Failed to set tun type");
+ }
+
+ /* Read initialised interface name */
+ strcpy(if_name, ifr.ifr_name);
+
+
+ /* Send tap_fd to slice */
+ send_vif_fd(control_channel_fd, tap_fd, if_name);
+
+ return 0;
+}
--- /dev/null
+/* Copy of fd_bmsocket.c that creates UDP sockets instead of TCP sockets. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "fdpass.h"
+
+#define MAX_BUFSIZE (32*1024*1024)
+
+/*------------------------------------------------------------------*/
+void
+receive_argument(int control_fd, int *rcvbuf, int *sndbuf)
+{
+ if (recv(control_fd, rcvbuf, sizeof(int), 0) != sizeof(int)) {
+ fprintf(stderr, "receiving the first argument failed\n");
+ exit(-1);
+ }
+ if (recv(control_fd, sndbuf, sizeof(int), 0) != sizeof(int)) {
+ fprintf(stderr, "receiving the first argument failed\n");
+ exit(-1);
+ }
+}
+/*------------------------------------------------------------------*/
+int
+main(int argc, char *argv[])
+{
+ int control_channel_fd, magic_socket;
+ int rcvbufsize = 0, sndbufsize = 0;
+
+ if (argc < 3) {
+ printf("This script is called by vsys.\n");
+ exit(1);
+ }
+
+ sscanf(argv[2],"%d", &control_channel_fd);
+
+ /* receive paramaters: rcvbufsize and sndbufsize */
+ receive_argument(control_channel_fd, &rcvbufsize, &sndbufsize);
+ if (rcvbufsize > MAX_BUFSIZE)
+ rcvbufsize = MAX_BUFSIZE;
+ if (sndbufsize > MAX_BUFSIZE)
+ sndbufsize = MAX_BUFSIZE;
+
+ magic_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ if (magic_socket == -1) {
+ fprintf(stderr, "Error creating socket: %d\n", errno);
+ exit(1);
+ }
+
+ /* buffer size <= 0 means we should ignore the parameter */
+ if (rcvbufsize > 0) {
+ if (setsockopt(magic_socket,
+ SOL_SOCKET,
+ SO_RCVBUFFORCE,
+ &rcvbufsize, sizeof(unsigned int))) {
+ fprintf(stderr, "Error calling setsockopt for RCVBUFFORCE: %d\n",
+ errno);
+ exit(1);
+ }
+ }
+ if (sndbufsize > 0) {
+ if (setsockopt(magic_socket,
+ SOL_SOCKET,
+ SO_SNDBUFFORCE,
+ &sndbufsize, sizeof(unsigned int))) {
+ fprintf(stderr, "Error calling setsockopt for SNDBUFFORCE: %d\n",
+ errno);
+ exit(1);
+ }
+ }
+
+ send_fd(control_channel_fd, magic_socket);
+}
--- /dev/null
+// Modified version of library functions in FUSE
+//
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+int send_fd(int sock_fd, int fd)
+{
+ int retval;
+ struct msghdr msg;
+ struct cmsghdr *p_cmsg;
+ struct iovec vec;
+ size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
+ int *p_fds;
+ char sendchar = 0;
+
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
+ p_cmsg = CMSG_FIRSTHDR(&msg);
+ p_cmsg->cmsg_level = SOL_SOCKET;
+ p_cmsg->cmsg_type = SCM_RIGHTS;
+ p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ p_fds = (int *) CMSG_DATA(p_cmsg);
+ *p_fds = fd;
+ msg.msg_controllen = p_cmsg->cmsg_len;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ /* "To pass file descriptors or credentials you need to send/read at
+ * least one byte" (man 7 unix) */
+ vec.iov_base = &sendchar;
+ vec.iov_len = sizeof(sendchar);
+ while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
+ if (retval != 1) {
+ perror("sending file descriptor");
+ return -1;
+ }
+ return 0;
+}
+
+
+/* return value:
+ * >= 0 => fd
+ * -1 => error
+ */
+int receive_fd(int fd)
+{
+ struct msghdr msg;
+ struct iovec iov;
+ char buf[1];
+ int rv;
+ size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
+ struct cmsghdr *cmsg;
+
+ iov.iov_base = buf;
+ iov.iov_len = 1;
+
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ /* old BSD implementations should use msg_accrights instead of
+ * msg_control; the interface is different. */
+ msg.msg_control = ccmsg;
+ msg.msg_controllen = sizeof(ccmsg);
+
+ while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
+ if (rv == -1) {
+ perror("recvmsg");
+ return -1;
+ }
+ if(!rv) {
+ /* EOF */
+ return -1;
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg->cmsg_type == SCM_RIGHTS) {
+ fprintf(stderr, "got control message of unknown type %d\n",
+ cmsg->cmsg_type);
+ return -1;
+ }
+ return *(int*)CMSG_DATA(cmsg);
+}
+
--- /dev/null
+// Modified version of library functions in FUSE
+//
+int send_fd(int sock_fd, int fd);
+int receive_fd(int fd);
+
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#include "tunalloc.h"
+
+int main(void)
+{
+ printf("Allocating tap device via VSYS\n");
+
+ char if_name[IFNAMSIZ];
+
+ int tun_fd = tun_alloc(IFF_TAP, if_name);
+
+ printf("Allocated tap device: %s fd=%d\n", if_name, tun_fd);
+
+ printf("Sleeping for 120 secs...\n");
+
+ sleep(120);
+
+ printf("Closing\n");
+
+ return 0;
+}
--- /dev/null
+/* Slice-side code to allocate tuntap interface in root slice
+ * Based on bmsocket.c
+ * Thom Haddow - 08/10/09
+ *
+ * Call tun_alloc() with IFFTUN or IFFTAP as an argument to get back fd to
+ * new tuntap interface. Interface name can be acquired via TUNGETIFF ioctl.
+ */
+
+#include <sys/un.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#define VSYS_TUNTAP "/vsys/fd_tuntap.control"
+
+/* Reads vif FD from "fd", writes interface name to vif_name, and returns vif FD.
+ * vif_name should be IFNAMSIZ chars long. */
+int receive_vif_fd(int fd, char *vif_name)
+{
+ struct msghdr msg;
+ struct iovec iov;
+ int rv;
+ size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
+ struct cmsghdr *cmsg;
+
+ /* Use IOV to read interface name */
+ iov.iov_base = vif_name;
+ iov.iov_len = IFNAMSIZ;
+
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ /* old BSD implementations should use msg_accrights instead of
+ * msg_control; the interface is different. */
+ msg.msg_control = ccmsg;
+ msg.msg_controllen = sizeof(ccmsg);
+
+ while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
+ if (rv == -1) {
+ perror("recvmsg");
+ return -1;
+ }
+ if(!rv) {
+ /* EOF */
+ return -1;
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg->cmsg_type == SCM_RIGHTS) {
+ fprintf(stderr, "got control message of unknown type %d\n",
+ cmsg->cmsg_type);
+ return -1;
+ }
+ return *(int*)CMSG_DATA(cmsg);
+}
+
+
+int tun_alloc(int iftype, char *if_name)
+{
+ int control_fd;
+ struct sockaddr_un addr;
+ int remotefd;
+
+ control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (control_fd == -1) {
+ perror("Could not create UNIX socket\n");
+ exit(-1);
+ }
+
+ memset(&addr, 0, sizeof(struct sockaddr_un));
+ /* Clear structure */
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, VSYS_TUNTAP,
+ sizeof(addr.sun_path) - 1);
+
+ if (connect(control_fd, (struct sockaddr *) &addr,
+ sizeof(struct sockaddr_un)) == -1) {
+ perror("Could not connect to Vsys control socket");
+ exit(-1);
+ }
+
+ /* passing type param */
+ if (send(control_fd, &iftype, sizeof(iftype), 0) != sizeof(iftype)) {
+ perror("Could not send paramater to Vsys control socket");
+ exit(-1);
+ }
+
+ remotefd = receive_vif_fd(control_fd, if_name);
+ return remotefd;
+}
--- /dev/null
+#ifndef _TUNALLOC_H
+#define _TUNALLOC_H
+
+int tun_alloc(int iftype, char *if_name);
+
+#endif
+++ /dev/null
-First checkin. Vsys scripts will live here in the future.
-
---This line, and those below, will be ignored--
-
-A vsys-factory
+++ /dev/null
-#
-# Vsys filesystem
-#
-# RPM spec file
-#
-# $Id: vsys-factory.spec 9786 2008-07-02 08:54:09Z thierry $
-#
-
-%define name vsys-factory
-%define version 0.7
-%define taglevel 0
-
-%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
-
-Vendor: PlanetLab
-Packager: PlanetLab Central <support@planet-lab.org>
-Distribution: PlanetLab %{plrelease}
-URL: %(echo %{url} | cut -d ' ' -f 2)
-
-Summary: Vsys factory scripts
-Name: %{name}
-Version: %{version}
-Release: %{release}
-License: GPL
-Group: System Environment/Kernel
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
-Requires: vsys
-
-Source0: vsys-factory-%{version}.tar.gz
-
-%description
-Vsys scripts for privileged operations on PlanetLab. These scripts are defined by maintainers of various components,
-to which users require privileged access.
-
-%prep
-%setup
-
-%build
-rm -rf $RPM_BUILD_ROOT
-make
-
-%install
-mkdir -p $RPM_BUILD_ROOT/vsys
-cp exec/* $RPM_BUILD_ROOT/vsys
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files
-/vsys/*
-
-%post
-
-%postun
-
-%changelog
-
#
# RPM spec file
#
-# $Id: vsys.spec 9786 2008-07-02 08:54:09Z thierry $
+# $Id$
#
-%define url $URL: svn+ssh://sapanb@poppins/svn/vsys/trunk/vsys.spec $
+%define url $URL$
%define name vsys
%define version 0.8
--- /dev/null
+#
+# Vsys filesystem
+#
+# RPM spec file
+#
+# $Id$
+#
+
+%define name vsys-scripts
+%define version 0.95
+%define taglevel 19
+
+%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
+
+Vendor: PlanetLab
+Packager: PlanetLab Central <support@planet-lab.org>
+Distribution: PlanetLab %{plrelease}
+URL: %(echo %{url} | cut -d ' ' -f 2)
+
+Summary: Vsys scripts scripts
+Name: %{name}
+Version: %{version}
+Release: %{release}
+License: GPL
+Group: System Environment/Kernel
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
+Requires: vsys
+
+Source0: vsys-scripts-%{version}.tar.gz
+
+%description
+Vsys scripts for privileged operations on PlanetLab. These scripts are defined by maintainers of various components,
+to which users require privileged access.
+
+%prep
+%setup
+
+%build
+rm -rf $RPM_BUILD_ROOT
+make
+
+%install
+mkdir -p $RPM_BUILD_ROOT/vsys
+cp exec/* $RPM_BUILD_ROOT/vsys
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+/vsys/*
+
+%post
+
+%postun
+
+%changelog
+* Thu Jul 01 2010 Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - vsys-scripts-0.95-19
+- change dotsshmount's mount point
+
+* Fri Jun 25 2010 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-18
+- Switch fd_tuntap to 2.6.27.
+
+* Fri Apr 30 2010 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-17
+- Tweak to if_port_forward script.
+
+* Fri Apr 30 2010 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-16
+- Added if_port_forward script to enable slices to forward ports for their
+- allocated IP addresses.
+
+* Wed Mar 03 2010 Talip Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - vsys-scripts-0.95-15
+- - hostname filter and updated documentation for ipfw scripts - Marta
+- - vsys script for letting users to set the Type of Services(ToS) byte in the IPv4 header - Caglar
+- (if this is not needed anymore please remove and tag again)
+
+* Thu Jan 21 2010 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-14
+- Tweak to Thom Haddow's script to let a slice see packets related to
+- existing connections.
+
+* Mon Jan 11 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - vsys-scripts-0.95-13
+- ipfw frontend has a rules cleanup feature
+- ongoing work around vif_up
+- new script 'run_with_devices'
+
+* Thu Nov 26 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - vsys-scripts-0.95-12
+- improve usability of the ipfw backend
+
+* Wed Oct 28 2009 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-11
+- * Load the tun module if it is not already loaded
+- * Fixed a bug in fd_tuntap
+
+* Tue Oct 27 2009 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-10
+- Adds Thom Haddow's tun/tap changes. I omitted a change in my previous commit.
+
+* Tue Oct 27 2009 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-9
+- This update adds Thom Haddow's custom tun/tap-device scripts.
+
+* Wed Sep 09 2009 Faiyaz Ahmed <faiyaza@cs.princeton.edu> - vsys-scripts-0.95-8
+- Added script to create UDP sockets instead of TCP sockets w/ big buffers
+
+* Mon Sep 07 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - vsys-scripts-0.95-7
+- minor changes in sliceip and ipfw, new reserve_udp_port
+
+* Mon Aug 03 2009 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-6
+- Added reserve_tcp_port and Giovanni's slice_ip tool.
+
+* Tue Jul 07 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - vsys-scripts-0.95-5
+- tweak in ipfw-be for in-node emulation
+
+* Thu Jun 11 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - vsys-scripts-0.95-4
+- Added the ipfw backend script
+
+* Fri Jun 05 2009 Faiyaz Ahmed <faiyaza@cs.princeton.edu> - vsys-scripts-0.95-3
+- rsync authlogs to ~/
+
+* Mon May 18 2009 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-2
+- Security update. umount had an issue that might have been exploited.
+
+* Thu May 14 2009 Sapan Bhatia <sapanb@cs.princeton.edu> - vsys-scripts-0.95-1
+- Adding port reservation script (goodfences)
+- Modifying umount to be more (or less, depending on your point of view) robust
+
+
+
+%define module_current_branch 0.7