# 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
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
# 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
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
}
# 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
$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
}
# 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