* CAVEAT: THIS VERSION IS BROKEN!!!
authorUrban Wallasch <urban.wallasch@freenet.de>
Mon, 22 Apr 2019 14:33:23 +0000 (16:33 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Mon, 22 Apr 2019 14:33:23 +0000 (16:33 +0200)
* First parameter may specify a config file name.
* Copy host's resolv.conf, if NAMESRV is empty.
* Start dhclient in guest only if no static address is provided.
* Do not try to run anything, if XCMD1 empty.
* Replaced `brctl` with equivalent `ip` invocations.
* Removed even more clutter.

nns.sh

diff --git a/nns.sh b/nns.sh
index 97f5f0ecf4074edb150e2cd9046fb4b61f13063c..74d2a4d7c14096d09d961d1dcbf49560ba63ebae 100755 (executable)
--- a/nns.sh
+++ b/nns.sh
 # TODO:
 # -----
 #
-# * Replace legacy tool invocations by `ip` incantations.
-#
-# * Outsource configuration to sourceable script fragment.
-#
 # * (Run dhclient to obtain bridge IP, if none was specified?)
 #
 # * Add "run" command to start a process in already existing namespace
 #   via `ip netns exec`.
 #
-# * Fix or remove obsolete comments.
-#
 ###############################
 
 
 ###############################
-# Configuration variables:
+# Default configuration; can be overriden by specifying
+# a shell script fragment as first parameter:
+
+NNSNAME=
 
 BASE_IF=vpn_tap1
 
-GUEST_ADDR=dhcp
+GUEST_ADDR=
 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="208.67.222.222 204.152.184.76 8.8.8.8"
+# List of nameservers to provide DNS in the new network namespace;
+# If empty, host resolv.conf will be used.
+NAMESRV="8.8.8.8 8.8.4.4"
 
 # Program to run in the new network namespace:
 XCMD1=xterm
@@ -55,8 +53,8 @@ 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."
+    echo "where name is the name of a config file or the network"
+    echo "namespace name and action is one of start | stop | reload."
 }
 
 if [ $# -lt 2 ]; then
@@ -67,6 +65,15 @@ fi
 # Become root if not already:
 [ "root" != "$USER" ] && exec sudo -E $0 "$@"
 
+# Check, if first parameter looks like a config file name.
+# If so: source it. Otherwise take $1 as namespace name.
+if [ -f "$1" ] && [ -r "$1" ] ; then
+    . "$1"
+else
+    # Clear the proposed namespace name of blank characters:
+    NNSNAME=${1//[[:space:]]}
+fi
+
 # Locate essential commands:
 IP=$(command -v ip)
 if [ -z $IP ] ; then
@@ -83,23 +90,23 @@ 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
 
-
-# Clear the proposed namespace name of blank characters:
-NNSNAME=${1//[[:space:]]}
+if [ -n "XCMD1" ] ; then
+    XCMD=$(command -v $XCMD1)
+    if [ -z $XCMD ] ; then
+        echo "please install the $XCMD1 package"
+        exit 1
+    fi
+fi
 
 # 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
+    $IP netns list | /bin/grep -F $1 1>/dev/null 2>&1
 }
 
 
@@ -117,27 +124,31 @@ start_nns() {
 
     # 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
+    if [ -n "$NAMESRV" ] ; then
+        /bin/rm /etc/netns/$1/resolv.conf 2> /dev/null
+        for NS in $NAMESRV ; do
+            echo "nameserver $NS" >> /etc/netns/$1/resolv.conf
+        done
+    else
+        cp /etc/resolv.conf /etc/netns/$1/resolv.conf
+    fi
 
     # 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 $BRIDGE_IF
-    brctl addif $BRIDGE_IF $BASE_IF
-    brctl addif $BRIDGE_IF $VETH_HOST
-    $IP link set dev $VETH_HOST up
+    $IP link add $BRIDGE_IF type bridge
+    $IP link set $BASE_IF master $BRIDGE_IF
+    $IP link set $VETH_HOST master $BRIDGE_IF
     $IP addr add $BRIDGE_ADDR dev $BRIDGE_IF
+    $IP link set dev $VETH_HOST up
     $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
-    if [ "$GUEST_ADDR" == "dhcp" ] ; then
-        $IP netns exec $1 $DHCLIENT -pf "$RUNDIR/dhclient.pid" -v $VETH_GUEST 1> /dev/null 2>&1
+    if [ -z "$GUEST_ADDR" ] ; then
+        $IP netns exec $1 $DHCLIENT -pf "$RUNDIR/dhclient.$VETH_GUEST.pid" -v $VETH_GUEST
     else
         $IP netns exec $1 $IP addr add $GUEST_ADDR dev $VETH_GUEST
         $IP netns exec $1 $IP link set dev $VETH_GUEST up
@@ -148,9 +159,11 @@ start_nns() {
     $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"
+    # Run the configured command, if any, inside the namespace:
+    if [ -n "$XCMD" ] ; then
+        $IP netns exec $1 su -p -c "$XCMD" $SUDO_USER &
+        $IP netns exec $1 echo "$!" > "$RUNDIR/xcmd_.pid"
+    fi
 }
 
 
@@ -174,9 +187,9 @@ stop_nns() {
 
     # 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
+    $IP link set dev $BASE_IF nomaster
+    $IP link set dev $VETH_HOST nomaster
+    $IP link del $BRIDGE_IF
 
     # Unplug the virtual cable and remove network namespace:
     $IP netns exec $1 $IP link del $VETH_GUEST