fix parsing ip on more kinds of networks
[newns] / newns
diff --git a/newns b/newns
index 39f8971f94baf6036947eb0ddc50e6503fba08c9..823d184b5b07b323d17acbe91a46b5b2a3ccd694 100755 (executable)
--- a/newns
+++ b/newns
@@ -38,24 +38,20 @@ fi
 usage() {
     cat <<EOF
 usage: ${0##*/} [OPTS] start|stop NS_NAME
-Setup new or systemd created network namespace with nat and mount namespace
+Nat a network namespace. create a mount ns. systemd friendly
 
 -c, --create    Create a named network namespace. When running from
                 the same network namespace as pid 1, this is set automatically.
                 This is the case when running outside a systemd created
                 private network.
+-n NETWORK      x.x.x /24 private network to use. If not specified, uses
+                the first one starting at 10.173.1
 -h, --help      Show this help and exit.
 
 From within a systemd network namespace, nat it to the outside. This
 would be called from ExecStartPre, and or subsequent units called with
 JoinsNamespaceOf= and PrivateNetwork=true.
 
-If given -c, or if in the default network namespace, create a named
-network namepace natted to the current netns.
-
-Uses /24 network, finding the first locally unused one starting at
-10.173.0.
-
 Also create a named mount namespace under /root/mount_namespaces, so we
 can alter some system config for this namespace. Subsequent systemd
 command lines would be prefixed with:
@@ -79,8 +75,8 @@ Background:
 This script does not make the namespace be named like ip does, because
 the naming is not necessary, although it could have been done with some
 more work. For debugging and joining the namespace with a bash shell, I
-use nsenter -n -m -t $(pgrep PROCESS_IN_NAMESPACE).  Note: if I knew how
-to easily ask systemd what pid a unit has, i would do that.
+use nsenter -n -m -t \$(pgrep PROCESS_IN_NAMESPACE) bash.  Note: if I
+knew how to easily ask systemd what pid a unit has, i would do that.
 
 "ip netns new ..." also does a mount namespace, then bind
 mounts each file/dir in /etc/netns/NS_NAME to /etc/NS_NAME. Note,
@@ -98,11 +94,12 @@ EOF
 
 #### begin arg parsing ####
 create=false
-temp=$(getopt -l help,create hc "$@") || usage 1
+temp=$(getopt -l help,create hcn: "$@") || usage 1
 eval set -- "$temp"
 while true; do
     case $1 in
         -c|--create) create=true; shift ;;
+        -n) network=$2; shift 2 ;;
         -h|--help) usage ;;
         --) shift; break ;;
         *) echo "$0: Internal error!" ; exit 1 ;;
@@ -160,15 +157,18 @@ dexec() { ip netns exec default "$@"; }
 
 # background: head -n1 is defensive. Not sure if there is some weird feature
 # for 2 routes to be 0/0.
-gateway_if=$(ipd route list exact 0/0 | head -n1| sed -r 's/.*\s(\S+)\s*$/\1/')
+gateway_if=$(ipd route list exact 0/0 | head -n1| sed -r 's/.*dev\s+(\S+).*/\1/')
 nat() { dexec iptables -t nat $1 POSTROUTING -o $gateway_if -j MASQUERADE \
               -m comment --comment "systemd network namespace nat"; }
 
 find_network() {
+    if [[ $network ]]; then
+        return
+    fi
     found=false
     existing=false
     ips="$(ipd addr show | awk '$1 == "inet" {print $2}')"
-    for ((i=0; i <= 254; i++)); do
+    for ((i=1; i <= 254; i++)); do
         network=$ip_base.$i
         if printf "%s\n" "$ips" | grep "^${network//./\\.}" >/dev/null; then
             existing=true
@@ -190,13 +190,26 @@ start() {
     mkdir -p /root/mount_namespaces
     if ! mountpoint /root/mount_namespaces >/dev/null; then
         mount --bind /root/mount_namespaces /root/mount_namespaces
-        mount --make-private /root/mount_namespaces
     fi
+    # note: This is outside the mount condition because I've mysteriously
+    # had this become shared instead of private, perhaps it
+    # got remounted somehow and lost the setting.
+    mount --make-private /root/mount_namespaces
     if [[ ! -e /root/mount_namespaces/$nn ]]; then
         touch /root/mount_namespaces/$nn
     fi
     if ! mountpoint /root/mount_namespaces/$nn >/dev/null; then
-        unshare --mount=/root/mount_namespaces/$nn
+        # documentation on propagation is a bit weird because it
+        # confusingly talks about binds, namespaces, and mirrors (which
+        # seems to be just another name for bind), shared subtrees
+        # (which seems to a term for binds and namespaces), and does not
+        # properly specify whether the documentation applies to binds,
+        # namespaces, or both. Notably, propagation for binds is marked
+        # on the original mount point, and propagation for a mount
+        # namespace is marked on mounts within the namespace.  Here, we
+        # specify that we want mount changes propagated to us, but not
+        # back.
+        unshare --propagation slave --mount=/root/mount_namespaces/$nn
     fi
     ####   end mount namespace setup ####