* Moved runtime info directory from /var/log/ to /var/run/.
authorUrban Wallasch <urban.wallasch@freenet.de>
Mon, 22 Apr 2019 10:53:41 +0000 (12:53 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Mon, 22 Apr 2019 10:53:41 +0000 (12:53 +0200)
* Save IPv4 forwarding state on start and restore it on stop.
* Replaced `ifconfig` by equivalent `ip` invocations.
* Renamed some variables.
* Removed more clutter.

nns.sh

diff --git a/nns.sh b/nns.sh
index 9de197a0cd392970156997f8addda63ee5b90a2c..97f5f0ecf4074edb150e2cd9046fb4b61f13063c 100755 (executable)
--- a/nns.sh
+++ b/nns.sh
@@ -1,8 +1,8 @@
 #!/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.
 #
 
 ###############################
@@ -16,8 +16,6 @@
 #
 # * (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
 
@@ -80,39 +78,32 @@ if [ -z $IPTABLES ] ; then
     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,"
@@ -120,38 +111,50 @@ start_nns() {
         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,"
@@ -159,53 +162,52 @@ stop_nns() {
         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