#!/bin/sh -u # Virtual Network Sandbox config for Network Address Translation (NAT) demo # -IAN! idallen@idallen.ca December 2004 February 2007 # # The VNS CDROM is by Linda MacEwan # # Changes: # /etc/hosts now has the names of all the hosts in it: "ping yellow" works # When you first boot the VNS, mount the location of the config file, # edit the file to make sure $VNS_CONFIG is set to the right path, # then source the file to start everything: # # mount /some/device # vi /some/device/path/to/vns/config/file # . /some/device/path/to/vns/config/file # # e.g. # # mount /dev/hda4 # . /dev/hda4/home/idallen/vns # # The "vns" section below will start all the UML virtual machines and link # the config file as /host/vnsconfig.sh in the directory that is common to the # VNS and all its UML clients. Then you must log in to each UML machine as # root and source this common file on each of the UML machines: # # . /host/vnsconfig.sh # # Once you have sourced the file once, it is remembered in the .profile for # the root account, so if you don't delete the virtual COW files, simply # restarting a UML machine and logging in as root will reconfigure for you. # The file is linked, not copied, so editing the file will change it. # Below are sections to configure each of the UML hosts, by name. # I define lots of handy aliases that do configuration for me, as needed. # IP address conventions here: # 192.168.X.Y # where X is the hub number (2 or 3) and Y is the machine number: # COLOR=(black red green yellow blue magenta cyan white) # 1=red, 2=green, 3=yellow, 4=blue, 5=magenta, 6=cyan, 7=white # e.g. hub3 machine blue[4] has address 192.168.3.4 # Use the above numbering so that the MAC link addresses match up. # # first two machines connect via eth2 and hub2 # third machine (router) connects via both eth2 and hub2 and eth3 and hub3 # the rest connect via eth3 and hub3 # The /host/vnsconfig.sh script is called in umlcolor before the HOSTNAME is set. # Work around it: if [ -s /etc/hostname ] ; then [ "${HOSTNAME-}" = '' ] && HOSTNAME=$( cat /etc/hostname ) [ "${HOSTNAME-}" = '(none)' ] && HOSTNAME=$( cat /etc/hostname ) [ "$(hostname)" = '(none)' ] && hostname --file /etc/hostname fi echo "This is host name '$HOSTNAME'" logger -t $0 "This is host name '$HOSTNAME'" # get rid of pre-defined distribution aliases unalias -a # clean out any existing host entries that we added last time flagged XVNSX grep -v " XVNSX$" /etc/hosts >/etc/hnew test -s /etc/hnew && mv /etc/hnew /etc/hosts /dev/null 2>&1 /etc/init.d/shorewall stop >/dev/null 2>&1 # this is an ifconfig that echoes what we are doing then does it myifconfig () { echo "$HOSTNAME: ifconfig $*" ifconfig "$@" || kill -INT $$ } # this is an ip that echoes what we are doing then does it myip () { echo "$HOSTNAME: ip $*" ip "$@" || kill -INT $$ } # start a set of UML machine terminals on the top or bottom of the screen # startmachine topbot Names... # e.g. startmachine top Red Green Yellow startmachine () { local topbot=$1 shift local plusminus='-' # bottom half of screen test "$topbot" = 'top' && plusminus='+' # top half of screen local name for name do # small effort to detect error in host name format if ! echo "$name" | grep '^[A-Z][a-z][a-z]' >/dev/null ; then echo "'$name' must contain first upper-case letter" kill -INT $$ fi local lowername=$( echo "$name" | tr 'A-Z' 'a-z' ) # find out how to start a UML if [ -x ~/.uml/uml ] ; then UML=~/.uml/uml ( x-terminal-emulator -fn 10x20 -T "$name" \ -geom 78x13+0${plusminus}0 \ -e $UML "$lowername" & ) else UML=uml ( $UML "$lowername" & ) fi done } # configure a UML machine that is already running # configmachine name hub machine {default_route|"none"} # e.g. configmachine red 2 1 none configmachine () { local name=$1 hub=$2 machine=$3 defroute=$4 local ipaddr=192.168.$hub.$machine local port=$machine$machine$machine$machine # See if this ipaddr and name is in the (non-symlink) hosts file; # add it if not. (The vns host has a read-only symlink for /etc/hosts.) # We add the dummy name XVNSX to all entries that we make, so that we # can delete them all from the file by pattern at the top of the script. # if test ! -L /etc/hosts \ && ! grep -e "^$ipaddr $name$hub$machine" /etc/hosts >/dev/null ; then if ! grep -w "$name" /etc/hosts >/dev/null ; then # add a new ipaddr with both long and short hostname echo "$ipaddr $name$hub$machine $name XVNSX" >>/etc/hosts else # add another ipaddr and long name for an existing host echo "$ipaddr $name$hub$machine XVNSX" >>/etc/hosts fi fi # do the part below only on the UML machine itself if [ "$HOSTNAME" = "$name" ] ; then myifconfig eth$hub $ipaddr if [ "$defroute" != none ] ; then myip route replace default via "$defroute" fi alias td="tcpdump -l -i eth$hub" alias tde="td -e" alias tdf="tde | fmt -t" alias tdn="td -n" alias tden="td -e -n" alias td$hub="tcpdump -l -i eth$hub" alias tde$hub="td$hub -e" alias tdf$hub="tde$hub | fmt -t" alias tdn$hub="td$hub -n" alias tden$hub="td$hub -e -n" alias listen="echo 'Listening on $ipaddr $port ...' ; netcat -l -p $port" # delete our name from the localhost entry if grep "^127.0.0..[ ]*$name" /etc/hosts >/dev/null ; then sed -e "/^127.0.0../s/$name//" /etc/hosts >/etc/hnew mv /etc/hnew /etc/hosts fi # link this startup script into our profile for next login # so we can shut down the UML machines and start them up again # test -s "$HOME/.profile" || ln -s /host/vnsconfig.sh "$HOME/.profile" fi } # This "vns" section is done only for the host VNS system, not by any # client UML systems. # if [ "$HOSTNAME" = "vns" ] ; then # classroom use: try to disable screen blanking and power saving xset s 0 xset s off xset dpms 0 0 0 2>/dev/null xset -dpms 2>/dev/null # Below is the location of this VNS config file. # Bind the $VNS_CONFIG file into the host file system # that is shared with all the UML client machines. # The UML machines will link the file to root's $HOME/.profile # VNS_CONFIG=/host/vnsconfig.sh # FIX THIS PATH AS NEEDED if [ ! -s "$VNS_CONFIG" ] ; then echo "Cannot find '$VNS_CONFIG'; nothing done" kill -INT $$ fi test -s /host/vnsconfig.sh || { touch /host/vnsconfig.sh || exit 1 mount -o bind "$VNS_CONFIG" /host/vnsconfig.sh || kill -INT $$ } # make sure things are where we think they should be if [ ! -e /var/run/uml-utilities/uml_switch1.ctl ] ; then echo "Cannot find 'uml_switch1.ctl'; nothing done" kill -INT $$ fi # Add a third hub and use hubs 2 and 3 instead of 1 and 2. # (Using hub1 we see duplicate traffic for everything.) test -e /var/run/uml-utilities/uml_switch3.ctl \ || /etc/init.d/uml-switch add # Trying to start an already running machine fails quietly # so you can run this safely multiple times. # First set of machines open on the top half of the screen. # Second set of machines open on the bottom half of the screen. # COLOR=(black red green yellow blue magenta cyan white) # startmachine top Red Green Yellow startmachine bot Blue Magenta Cyan fi # the middle machine is the router router=yellow # a primary and secondary machine on hub2: the "Internet" configmachine red 2 1 none # hub2 machine1 no default route configmachine green 2 2 none # hub2 machine2 no default route # the router - connects to two hubs (internal and external net): configmachine "$router" 2 3 192.168.2.1 # hub2 mach3 default route via red21 configmachine "$router" 3 3 none # hub3 mach3 no default route if [ "$HOSTNAME" = "$router" ] ; then # enable packet forwarding between interfaces # load the iptables modules we need echo 1 >/proc/sys/net/ipv4/ip_forward modprobe iptable_filter modprobe iptable_nat # normal SNAT network address translation out eth2 snat='POSTROUTING -o eth2 -j SNAT --to-source 192.168.2.3' alias do-snat="iptables -t nat -A $snat" alias undo-snat="iptables -t nat -D $snat" # DNAT port-forwarding aliases for all the local machines on hub3. # The hub2 interface (2.3) is the "Internet" public address; we # port-forward to a machine on the internal network. The port # number is the machine number repeated 4 times, e.g. 4444, 5555, etc. for i in 4 5 6 ; do tmp1="PREROUTING -d 192.168.2.3 -p tcp --dport $i$i$i$i" tmp2="-j DNAT --to 192.168.3.$i" alias do-dnat$i="iptables -t nat -A $tmp1 $tmp2" alias undo-dnat$i="iptables -t nat -D $tmp1 $tmp2" done # additional SNAT rule to fix packets going in/out private eth3 # (to allow using external DNAT addresses from internal machines) tmp1='POSTROUTING -s 192.168.3.0/24 -d 192.168.3.0/24' tmp2='-j SNAT --to 192.168.3.3' alias do-fix="iptables -t nat -A $tmp1 $tmp2" alias undo-fix="iptables -t nat -D $tmp1 $tmp2" # alias to list the two NAT tables of interest alias ipl='iptables -v -t nat -n -L PREROUTING ; iptables -v -t nat -n -L POSTROUTING' alias ipt=ipl fi # some "internal" clients on hub3: the private internal network configmachine blue 3 4 192.168.3.3 # hub3 mach4 default route via router33 configmachine magenta 3 5 192.168.3.3 # hub3 mach5 default route via router33 configmachine cyan 3 6 192.168.3.3 # hub3 mach6 default route via router33 # add aliases for Ian! that make typing a bit shorter alias load='. /host/vns' alias ff='fmt -t' alias a=alias alias pd=pushd alias l=less alias ls='ls -a' alias lslt='ls -lat' alias lslth='ls -lat | head' alias i="ifconfig" alias ifl="ifconfig | less" alias i0="ifconfig eth0" alias i1="ifconfig eth1" alias i2="ifconfig eth2" alias i3="ifconfig eth3"