[[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
+tmp="$(readlink -f "${BASH_SOURCE}")"; script_dir="${tmp%/*}"
if [[ ! $ERRHANDLE_PATH ]]; then
- ERRHANDLE_PATH=$(readlink -f "${BASH_SOURCE}")
- ERRHANDLE_PATH=$(readlink -f ${ERRHANDLE_PATH%/*}/../errhandle)
+ ERRHANDLE_PATH="$script_dir"/../errhandle/err
fi
-err_sourced=true
-for p in $ERRHANDLE_PATH/{errcatch-function,bash-trace-function}; do
- if [[ -e $p ]]; then
- source $p
- else
- err_sourced=false
- fi
-done
-if $err_sourced; then
- errcatch
+if [[ -s $ERRHANDLE_PATH ]]; then
+ source $ERRHANDLE_PATH
else
- set -eE -o pipefail
- trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+ 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
usage() {
the first unused 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
+From a normal shell:
+
+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.
+
+
+For systemd:
+
+From within a systemd network namespace, we 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
+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:
/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.
-A recommmended dependency of this script is my other repo named "errhandle",
-which prints stack trace on error, and calls a cleanup function:
-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.
+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.
-Background:
+
+Background on this project (you can skip if you like):
If we aren't creating a named network namespace, to join the namespace
with a shell, I use:
Note: if I knew how to easily ask systemd what pid a unit has, i would
do that.
-If we do create the netns, to join it with a shell, we can do
-/usr/bin/nsenter --mount=/root/mount_namespaces/NAME --net=/var/run/netns/NAME bash
-
"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
copy /run/resolvconf somehwere then bind mount it on top of
/run/resolvconf.
+
Note: for debugging, adding set -x is a pretty good option.
Please email me if you have a patches, bugs, feedback, or republish this
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 not 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