[[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
-tmp="$(readlink -f "${BASH_SOURCE}")"; script_dir="${tmp%/*}"
-if [[ ! $ERRHANDLE_PATH ]]; then
- ERRHANDLE_PATH="$script_dir"/../errhandle/err
-fi
-if [[ -s $ERRHANDLE_PATH ]]; then
- source $ERRHANDLE_PATH
-else
- cd "$script_dir"
- if ! wget -O err 'https://iankelling.org/git/?p=errhandle;a=blob_plain;f=err;hb=HEAD'; then
- echo "$0: failed to get errhandle dependency" >&2
- exit 1
- fi
- source err
-fi
+# https://savannah.nongnu.org/projects/bash-bear-trap/
+set -e; . /usr/local/lib/bash-bear; set +e
+
usage() {
cat <<EOF
Also creates a mount namespace with a cloned /run/resolvconf.
--c, --create Create a named network namespace. When running from
+-c, --create Create or destroy a named network namespace. When running from
the same network namespace as pid 1, this is set automatically.
A systemd created private network is in a network namespace
different than pid 1.
From a normal shell:
-If we do create the netns, to join it with a shell, we can do
+If we do create the netns, to join it with a shell, we can do (as root)
/usr/bin/nsenter --mount=/root/mount_namespaces/NAME --net=/var/run/netns/NAME bash
If you dont care about the mount namespace, you can leave that option off.
would be called from ExecStartPre, and or subsequent units called with
JoinsNamespaceOf= and PrivateNetwork=true.
-We also create a named mount namespace under /root/mount_namespaces, so we
-can alter some system config for this namespace. systemd
-command lines would be prefixed with:
+If resolvconf is installed, we create a named mount namespace under
+/root/mount_namespaces, so we can alter some system config for this
+namespace. systemd command lines would be prefixed with:
/usr/bin/nsenter --mount=/root/mount_namespaces/NS_NAME
will update the script to that the mount namespace not created unless a
flag is passed in. Patch welcome to add that flag before then.
-This script has a dependency which you can download manually or it
-will be automatically downloaded into the same directory.
-It handles errors by printing stack trace and and cleaning up the namespaces.
-To download manually,
-git clone https://iankelling.org/git/errhandle
-into an adjacent directory, or
-export ERRHANDLE_PATH to point to the 'err' file in that repo.
+
+This script has a dependency
+https://savannah.nongnu.org/projects/bash-bear-trap/ . Search the script for "source" to see where to install or modify the installed location.
Background on this project (you can skip if you like):
fi
#### end sanity checking ####
-
v0=veth0-$nn
v1=veth1-$nn
ip_base=10.173
fi
# make the default network namespace be named
+
+mkdir -p /run/netns
target=/run/netns/default
if [[ ! -e $target && ! -L $target ]]; then
- mkdir -p /run/netns
- ln -s /proc/1/ns/net $target
+ # -f to avoid a race condition with running twice
+ ln -sf /proc/1/ns/net $target
fi
-
ipd() { ip -n default "$@"; }
+
+
+# otherwise we are already in the network namespace and it's unnamed.
if $create; then
- # run ip in the network namespace
- ipnn() { ip -n $nn "$@"; }
-else
- # we are already in the network namespace and it's unnamed.
- # run ip in the network namespace
- ipnn() { ip "$@"; }
+ ipnnargs="-n $nn"
fi
+# run ip in the network namespace
+ipnn() { ip $ipnnargs "$@"; }
+
# default network namespace exec
dexec() { ip netns exec default "$@"; }
# mount namespace exec
mexec() { /usr/bin/nsenter --mount=/root/mount_namespaces/$nn "$@"; }
-# background: head -n1 is defensive. Not sure if there is some weird feature
-# for 2 routes to be 0/0.
-gateway_ifs=($(ipd route list exact 0/0 | head -n1| sed -r 's/.*dev\s+(\S+).*/\1/'))
-
-if [[ ! $gateway_ifs ]]; then
- cat >&2 <<EOF
-$0: error: failed to find gateway interface. No output from:
-ipd route list exact 0/0 | head -n1| sed -r 's/.*dev\s+(\S+).*/\1/'
-output from "ipd route list exact 0/0":
-$(ipd route list exact 0/0)
-EOF
- exit 1
-fi
-
nat() {
- for if in ${gateway_ifs[@]}; do
- dexec iptables -t nat $1 POSTROUTING -o $if -j MASQUERADE \
- -m comment --comment "systemd network namespace nat"
- done
+ # note, in a previous commit i specified the output interface with -o,
+ # but that broke things when my gateway interface changed, and I can't
+ # see any advantage to it, so I removed it.
+ dexec iptables -t nat $1 POSTROUTING -s $network.0/24 -j MASQUERADE \
+ -m comment --comment "systemd network namespace nat"
}
# d = default
ip -n $nn link set dev lo up
fi
- echo 1 | dexec dd of=/proc/sys/net/ipv4/ip_forward 2>/dev/null
+ echo 1 | dexec dd of=/proc/sys/net/ipv4/ip_forward status=none
# docker helpfully changes the default FORWARD to drop...
diptables-add FORWARD -i $v0 -j ACCEPT
diptables-add FORWARD -o $v0 -j ACCEPT
- _errcatch_cleanup=stop
+ err-cleanup() { stop; }
ipnn link add $v0 type veth peer name $v1
ipnn link set $v0 netns default
ipd addr add $network.1/24 dev $v0
ipnn route add default via $network.1
###### begin setup resolvconf
- resolv_copy=/root/resolvconf-$nn
+ if [[ -e /run/resolvconf ]]; then # resolvconf probably installed
+ resolv_copy=/root/resolvconf-$nn
- # this condition should never happen, just coding defensively
- if mexec mountpoint /run/resolvconf &>/dev/null; then
- mexec umount /run/resolvconf
- fi
- cp -aT /run/resolvconf $resolv_copy
- if ! mexec mount -o bind $resolv_copy /run/resolvconf; then
- echo "error: resolv-conf bindmount failed"
- exit 1
- fi
- # if running dnsmasq, we have 127.0.0.1 for dns, but it can't listen on the loopback
- # in the network namespace, so adjust the address.
- if mexec [ -s /run/resolvconf/interface/lo.dnsmasq ]; then
- mexec sed --follow-symlinks -i "s/nameserver 127\..*/nameserver $network.1/" /run/resolvconf/interface/lo.dnsmasq
- mexec resolvconf -u
- fi
- # and in debian based distros at least, it runs with --local-service, and needs a restart
- # to know about the new local network
- if [[ $(systemctl --no-pager show -p ActiveState dnsmasq ) == ActiveState=active ]]; then
- systemctl restart dnsmasq
- fi
+ # this condition should never happen, just coding defensively
+ if mexec mountpoint /run/resolvconf &>/dev/null; then
+ mexec umount /run/resolvconf
+ fi
+ cp -aT /run/resolvconf $resolv_copy
+ if ! mexec mount -o bind $resolv_copy /run/resolvconf; then
+ echo "error: resolv-conf bindmount failed"
+ exit 1
+ fi
+ # if running dnsmasq, we have 127.0.0.1 for dns, but it can't listen on the loopback
+ # in the network namespace, so adjust the address.
+ if mexec [ -s /run/resolvconf/interface/lo.dnsmasq ]; then
+ mexec sed --follow-symlinks -i "s/nameserver 127\..*/nameserver $network.1/" /run/resolvconf/interface/lo.dnsmasq
+ mexec resolvconf -u
+ fi
+ # and in debian based distros at least, it runs with --local-service, and needs a restart
+ # to know about the new local network
+ if [[ $(systemctl --no-pager show -p ActiveState dnsmasq ) == ActiveState=active ]]; then
+ systemctl restart dnsmasq
+ fi
+
+ # background: if we did this in openvpn's resolv-conf script, we could guard it in
+ # if capsh --print|grep '\bcap_sys_admin\b' &>/dev/null
+ # and we could get $nn by
+ # config_basename=${config%%.*}
+ # config_basename=${config_basename##*/}
+ # but dnsmasq forces us to do it earlier.
- # background: if we did this in openvpn's resolv-conf script, we could guard it in
- # if capsh --print|grep '\bcap_sys_admin\b' &>/dev/null
- # and we could get $nn by
- # config_basename=${config%%.*}
- # config_basename=${config_basename##*/}
- # but dnsmasq forces us to do it earlier.
+ fi # end if [[ -e /run/resolvconf ]]
###### end setup resolvconf
if ! $existing; then
if nat -C &>/dev/null; then nat -D; fi
fi
- dexec iptables -D FORWARD -i $v0 -j ACCEPT ||:
- if $create && [[ -e /var/run/netns/client ]]; then
+ dexec iptables -D FORWARD -i $v0 -j ACCEPT &>/dev/null ||:
+ if $create && [[ -e /var/run/netns/$nn ]]; then
ip netns del $nn
fi