#!/bin/bash
#
-# This script will setup a network namespace with a macvlan
-# which obtains its IP address via dhclient from the LAN on which the host is
-# placed
+# This script will setup a network namespace around a specified base
+# interface, connect it with a veth virtual ethernet to a bridge in
+# the host (default) network namespace.
#
###############################
#
# * (Run dhclient to obtain bridge IP, if none was specified?)
#
-# * Add config option to disable IP forwarding on stop?
-#
# * Add "run" command to start a process in already existing namespace
# via `ip netns exec`.
#
###############################
-set -x
-
-# The script will temporarily activate ip forwarding for you. If you
-# do not wish to retain this feature, you will have to issue, at the
-# end of this session, the command
-# echo 0 > /proc/sys/net/ipv4/ip_forward
-# yourself.
-
-###############################################################################
-
###############################
-# Configuration variables
+# Configuration variables:
BASE_IF=vpn_tap1
-BASE_NET=192.168.30.0/24
-BR_NAME=br0
-BR_IP=192.168.30.3
+
+GUEST_ADDR=dhcp
+GUEST_NET=192.168.30.0/24
+
+BRIDGE_IF=br0
+BRIDGE_ADDR=192.168.30.3
# List of nameservers to provide DNS in the new network namespace:
-NAMESRV="8.8.8.8 8.8.4.4"
+NAMESRV="208.67.222.222 204.152.184.76 8.8.8.8"
# Program to run in the new network namespace:
-XTERM1=xterm
+XCMD1=xterm
# Virtual Ethernet to connect new network namespace to default namespace:
VETH_HOST=veth_host
VETH_GUEST=veth_guest
-#
+# Configuration end.
###############################
+
+set -x
+
SHORTNAME=${0##*/}
+usemsg() {
+ echo "Usage: $1 name action"
+ echo "where name is the network namespace name"
+ echo "and action is one of start| stop| reload."
+}
+
if [ $# -lt 2 ]; then
- echo "Usage $SHORTNAME name action"
- echo "where name is the network namespace name,"
- echo " and action is one of start| stop| reload."
+ usemsg $SHORTNAME
exit 1
fi
echo "please install the iptables package"
exit 1
fi
-XTERM=$(command -v $XTERM1)
-if [ -z $XTERM ] ; then
- echo "please install the $XTERM1 package"
+DHCLIENT=$(command -v dhclient)
+if [ -z $DHCLIENT ] ; then
+ echo "please install the dhclient package"
+ exit 1
+fi
+XCMD=$(command -v $XCMD1)
+if [ -z $XCMD ] ; then
+ echo "please install the $XCMD1 package"
exit 1
fi
-prelim() {
-# Perform some preliminary setup. First, clear the proposed
-# namespace name of blank characters; then create a directory
-# for logging info, and a pid file in it; lastly, enable IPv4
-# forwarding.
-
- VAR=$1
- export NNSNAME=${VAR//[[:space:]]}
-
- export OUTDIR=/var/log/newns/$NNSNAME
-
- if [ ! -d $OUTDIR ]; then
- /bin/mkdir -p $OUTDIR
- fi
- export PID=$OUTDIR/pid$NNSNAME
-
- echo 1 > /proc/sys/net/ipv4/ip_forward
+# Clear the proposed namespace name of blank characters:
+NNSNAME=${1//[[:space:]]}
-}
+# Assign and create directory to keep runtime information:
+RUNDIR=/var/run/newns/$NNSNAME
+/bin/mkdir -p $RUNDIR
# Check whether a namespace with given name exists:
exist_nns() {
$IP netns list | /bin/grep $1 2> /dev/null
}
-# Create and configure a new network namespace:
+
+# Set up a new network namespace:
start_nns() {
if exist_nns $1 ; then
echo "Network namespace $1 already exists,"
exit 1
fi
- # Take care of DNS:
+ # Enable IPv4 forwarding after saving the previous state:
+ cat /proc/sys/net/ipv4/ip_forward > "$RUNDIR/ipv4fwd.sav"
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # Take care of DNS in the new namespace:
/bin/mkdir -p /etc/netns/$1
/bin/rm /etc/netns/$1/resolv.conf 2> /dev/null
for NS in $NAMESRV ; do
echo "nameserver $NS" >> /etc/netns/$1/resolv.conf
done
- # Create the new namespace, the veth interface and the bridge:
+ # Create the new namespace, the veth cable and the bridge interface:
$IP netns add $1
$IP link add $VETH_HOST type veth peer name $VETH_GUEST
- brctl addbr $BR_NAME
- brctl addif $BR_NAME $BASE_IF
- brctl addif $BR_NAME $VETH_HOST
- ifconfig $VETH_HOST up
- ifconfig $BR_NAME $BR_IP up
-
-# This assigns the macvlan interface, mac$1, to the new
-# namespace, asks for an IP address via a call to dhclient,
-# brings up this and the (essential) lo interface,
-# creates a new terminal in the new namespace and
-# stores its pid for the purpose of tearing it cleanly, later.
-
+ brctl addbr $BRIDGE_IF
+ brctl addif $BRIDGE_IF $BASE_IF
+ brctl addif $BRIDGE_IF $VETH_HOST
+ $IP link set dev $VETH_HOST up
+ $IP addr add $BRIDGE_ADDR dev $BRIDGE_IF
+ $IP link set dev $BRIDGE_IF up
+
+ # Assign the veth guest interface to the new network namespace,
+ # set an IP address (either static or via dhclient) to it, bring
+ # up this and the lo interface:
$IP link set $VETH_GUEST netns $1
- $IP netns exec $1 /sbin/dhclient -pf /var/run/dhclient_$1.pid -v $VETH_GUEST 1> /dev/null 2>&1
+ if [ "$GUEST_ADDR" == "dhcp" ] ; then
+ $IP netns exec $1 $DHCLIENT -pf "$RUNDIR/dhclient.pid" -v $VETH_GUEST 1> /dev/null 2>&1
+ else
+ $IP netns exec $1 $IP addr add $GUEST_ADDR dev $VETH_GUEST
+ $IP netns exec $1 $IP link set dev $VETH_GUEST up
+ fi
$IP netns exec $1 $IP link set dev lo up
- $IP netns exec $1 su -p -c $XTERM $SUDO_USER &
- $IP netns exec $1 echo "$!" > $PID
- $IPTABLES -t nat -A POSTROUTING --source $BASE_NET --jump MASQUERADE
- $IP netns exec $1 /sbin/route add default gw $BR_IP
+ # Set up routing:
+ $IPTABLES -t nat -A POSTROUTING --source $GUEST_NET --jump MASQUERADE
+ $IP netns exec $1 /sbin/route add default gw $BRIDGE_ADDR
+
+ # Run the configured user process inside the namespace:
+ $IP netns exec $1 su -p -c "$XCMD" $SUDO_USER &
+ $IP netns exec $1 echo "$!" > "$RUNDIR/xcmd_.pid"
}
+
+# Tear down a previously created network namespace and clean up the mess:
stop_nns() {
if ! exist_nns $1 ; then
echo "Network namespace $1 does not exist,"
exit 1
fi
-# This kills the terminal in the separate namespace and
-# removes the file and the directory where it is stored.
+ # Kill processes started in the separate namespace:
+ for PIDF in $RUNDIR/*.pid ; do
+ /bin/kill -TERM $(cat "$PIDF")
+ /bin/rm "$PIDF"
+ done
- /bin/kill -TERM $(cat $PID) 2> /dev/null 1> /dev/null
- /bin/kill -TERM $(cat /var/run/dhclient_$1.pid) 2> /dev/null 1> /dev/null
- /bin/rm $PID
- /bin/rmdir $OUTDIR
+ # Restore saved state of IPv4 forwarding:
+ cat $RUNDIR/ipv4fwd.sav > /proc/sys/net/ipv4/ip_forward
+ rm $RUNDIR/ipv4fwd.sav
- ifconfig $BR_NAME down
- brctl delif $BR_NAME $BASE_IF
- brctl delif $BR_NAME $VETH_HOST
- brctl delbr $BR_NAME
+ # Burn the bridge:
+ $IP link set dev $BRIDGE_IF down
+ brctl delif $BRIDGE_IF $BASE_IF
+ brctl delif $BRIDGE_IF $VETH_HOST
+ brctl delbr $BRIDGE_IF
+ # Unplug the virtual cable and remove network namespace:
$IP netns exec $1 $IP link del $VETH_GUEST
- $IP netns del $1
$IP link del $VETH_HOST
- $IPTABLES -t nat -D POSTROUTING --source $BASE_NET --jump MASQUERADE
-
-# This deletes the file and direcotory connected with the DNSes.
+ $IP netns del $1
+ $IPTABLES -t nat -D POSTROUTING --source $GUEST_NET --jump MASQUERADE
+ # Cleanup namespace DNS configuration:
/bin/rm /etc/netns/$1/resolv.conf
/bin/rmdir /etc/netns/$1
+ # Remove runtime dir:
+ /bin/rmdir $RUNDIR
}
case $2 in
start)
- prelim "$1"
start_nns $NNSNAME
;;
stop)
- prelim "$1"
stop_nns $NNSNAME
;;
reload|restart)
- prelim "$1"
stop_nns $NNSNAME
- prelim "$1"
start_nns $NNSNAME
;;
- run)
+ run|exec)
echo "TO-DO: implement '$SHORTNAME run <command>' action."
;;
*)
- echo "Usage: $SHORTNAME name action,"
- echo "where name is the name of the network namespace,"
- echo "and action is one of start|stop|reload"
+ usemsg $SHORTNAME
;;
esac