fix parsing ip on more kinds of networks
[newns] / newns
diff --git a/newns b/newns
index 31f1b528c80bdab325c17631adf5c6245c745895..823d184b5b07b323d17acbe91a46b5b2a3ccd694 100755 (executable)
--- a/newns
+++ b/newns
@@ -37,24 +37,26 @@ fi
 
 usage() {
     cat <<EOF
 
 usage() {
     cat <<EOF
-usage: ${0##*/} [OPTS] start|stop NETNS_NAME
-Setup new or systemd created network namespace with nat and mount namespace
-
--c, --create    Create network namespace. For running outside systemd private net.
+usage: ${0##*/} [OPTS] start|stop NS_NAME
+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.
 
 -h, --help      Show this help and exit.
 
-From within systemd network namespace, nat it to the outside. 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.
+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.
 
 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:
 
 
 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:
 
-/usr/bin/nsenter --mount=/root/mount_namespaces/NETNS_NAME
+/usr/bin/nsenter --mount=/root/mount_namespaces/NS_NAME
 
 Note, this means that they can't run as unpriveledged users, but once
 systemd 233 comes out, it will have a bind mount option from within unit
 
 Note, this means that they can't run as unpriveledged users, but once
 systemd 233 comes out, it will have a bind mount option from within unit
@@ -68,8 +70,16 @@ https://iankelling.org/git/?p=errhandle, set ERRHANDLE_PATH, or put it
 in a directory adjacent to the absolute, resolved directory this file is
 in.
 
 in a directory adjacent to the absolute, resolved directory this file is
 in.
 
-Background: "ip netns new ..." also does a mount namespace, then bind
-mounts each file/dir in /etc/netns/NETNS_NAME to /etc/NETNS_NAME. Note,
+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) 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,
 for openvpn having it's own resolv.conf by using it's user script which
 calls resolvconf, this doesn't help much. What we actually want to do is
 copy /run/resolvconf somehwere then bind mount it on top of
 for openvpn having it's own resolv.conf by using it's user script which
 calls resolvconf, this doesn't help much. What we actually want to do is
 copy /run/resolvconf somehwere then bind mount it on top of
@@ -82,13 +92,14 @@ EOF
 }
 
 
 }
 
 
-## begin arg parsing ##
+#### begin arg parsing ####
 create=false
 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 ;;
 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 ;;
         -h|--help) usage ;;
         --) shift; break ;;
         *) echo "$0: Internal error!" ; exit 1 ;;
@@ -99,11 +110,10 @@ if (( $# != 2 )); then
 fi
 
 action=$1
 fi
 
 action=$1
-nn=$2 # network namespace / namespace name
-## end arg parsing ##
-
-## begin sanity checking ##
+nn=$2 # namespace name
+#### end arg parsing ####
 
 
+#### begin sanity checking ####
 install_error=false
 if ! type -p ip &>/dev/null; then
     echo "please install the iproute2 package"
 install_error=false
 if ! type -p ip &>/dev/null; then
     echo "please install the iproute2 package"
@@ -116,8 +126,7 @@ fi
 if $install_error; then
     exit 1
 fi
 if $install_error; then
     exit 1
 fi
-
-##   end sanity checking ##
+####   end sanity checking ####
 
 
 v0=veth0-$nn
 
 
 v0=veth0-$nn
@@ -128,10 +137,10 @@ if ! $create && [[ $(readlink /proc/self/ns/net) == "$(readlink /proc/1/ns/net)"
     create=true
 fi
 
     create=true
 fi
 
+# make the default network namespace be named
 target=/run/netns/default
 if [[ ! -e $target && ! -L $target ]]; then
     mkdir -p /run/netns
 target=/run/netns/default
 if [[ ! -e $target && ! -L $target ]]; then
     mkdir -p /run/netns
-    # make the default network namespace be named
     ln -s /proc/1/ns/net $target
 fi
 
     ln -s /proc/1/ns/net $target
 fi
 
@@ -146,17 +155,20 @@ fi
 dexec() { ip netns exec default "$@"; }
 
 
 dexec() { ip netns exec default "$@"; }
 
 
-# head -n1 is defensive. Not sure if there is some weird feature
+# background: head -n1 is defensive. Not sure if there is some weird feature
 # for 2 routes to be 0/0.
 # 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() {
 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}')"
     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
         network=$ip_base.$i
         if printf "%s\n" "$ips" | grep "^${network//./\\.}" >/dev/null; then
             existing=true
@@ -168,24 +180,38 @@ find_network() {
 }
 
 start() {
 }
 
 start() {
-
     find_network
     if ! $found; then
         echo "$0: error: no open network found"
         exit 1
     fi
 
     find_network
     if ! $found; then
         echo "$0: error: no open network found"
         exit 1
     fi
 
+    #### begin mount namespace setup ####
     mkdir -p /root/mount_namespaces
     if ! mountpoint /root/mount_namespaces >/dev/null; then
         mount --bind /root/mount_namespaces /root/mount_namespaces
     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
     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
     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
     fi
+    ####   end mount namespace setup ####
 
 
     if $create; then
 
 
     if $create; then
@@ -193,8 +219,6 @@ start() {
         ip -n $nn link set dev lo up
     fi
 
         ip -n $nn link set dev lo up
     fi
 
-
-
     echo 1 | dexec dd of=/proc/sys/net/ipv4/ip_forward 2>/dev/null
 
     _errcatch_cleanup=stop
     echo 1 | dexec dd of=/proc/sys/net/ipv4/ip_forward 2>/dev/null
 
     _errcatch_cleanup=stop