From 6e82a78a2e4f7e267c5ea4457c6727da7c93e14b Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Sun, 26 Jul 2009 05:44:58 +0000 Subject: [PATCH] adding sliceip on behalf of Giovanni --- sliceip | 480 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 480 insertions(+) create mode 100755 sliceip diff --git a/sliceip b/sliceip new file mode 100755 index 0000000..b34493a --- /dev/null +++ b/sliceip @@ -0,0 +1,480 @@ +#!/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 +# fronted script in the slice environment. +# +# Fronted usage: +# sliceip enable +# 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 +# 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 via dev +# This command adds a rule to reach through the host +# that can be reached on the 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 +# 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 + + 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 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 [[ $old_ip != $ip ]]; then + #remove the rule for the old ip + exec "iptables -t nat -D POSTROUTING -o $interface -j SNAT --to-source $old_ip -m mark --mark $nid" + #insert the new rule + exec "iptables -t nat -A 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 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 + echo EOF + exit 1 + fi + fi + +} + +# decides wich id to use for the slice 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 /${regex}/d $filename" > $filename.tmp + exec "mv $filename.tmp $filename" + + +} + +# get the slice-specific routing table name +function get_table_name(){ + local sliver=$1; + echo "${sliver}_slcip" +} + +function clean_iproute_conf(){ + while grep "slcip" $RT_TABLES >/dev/null 2>&1; do + remove_line $RT_TABLES "slcip" + done + + rm ${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 -A OUTPUT -m mark --mark $sliver_nid -j MARK --set-mark $temp_nid" + + #Here we ask VNET+ to set the netfilter mark for the remaining packets (to the slice-id) + exec "iptables -t mangle -A OUTPUT -j MARK -m mark ! --mark $temp_nid --copy-xid 0x00" + 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 OUTPUT -m owner --uid-owner $sliver_nid -j MARK --set-mark $sliver_nid" + fi + + #Here the netfilter mark is restored to the slice-id value for the "strange packets" + exec "iptables -t mangle -I POSTROUTING 1 -m mark --mark $temp_nid -j MARK --set-mark $sliver_nid" + + #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 +} + +# removes 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 OUTPUT -m mark --mark $sliver_nid -j MARK --set-mark $temp_nid" + + #removes the rules that asks VNET+ to set the netfilter mark to the slice-id + exec "iptables -t mangle -D OUTPUT -m mark ! --mark $temp_nid -j MARK --copy-xid 0x00" + 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 OUTPUT -m owner --uid-owner $sliver_nid -j MARK --set-mark $sliver_nid" + fi + + exec "iptables -t mangle -D POSTROUTING -m mark --mark $temp_nid -j MARK --set-mark $sliver_nid" + + 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" + +} + +# 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 slice packets +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 +} + + + +# checks 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 + +# separates the first word of the line from the others +command=`echo ${line%% *}` +rest=`echo ${line#* }` + +case "$command" in + enable) + logger "slcip command received from $sliver: $line" + enable_interface $sliver "$rest" + ;; + + disable) + logger "slcip command received from $sliver: $line" + disable_interface $sliver "$rest" + ;; + + *) + logger "slcip command received from $sliver: $line" + table_sliver=`get_table_name $sliver` + + # adds the rule + if ! grep "$table_sliver" $RT_TABLES >/dev/null 2>&1; then + echo "Error. The slice routing table is not defined. Execute sliceip enable ." + else + exec "ip $line table $table_sliver" + fi + ;; + +esac + +# make the frontend quit +echo "EOF" + +exit 0 + + + -- 2.43.0