2 # Copyright (C) 2017 Ian Kelling
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 # Create a network namespace. Designed for use from systemd.
19 [[ $EUID == 0 ]] ||
exec sudo
-E "$BASH_SOURCE" "$@"
21 cd "${BASH_SOURCE%/*}"
22 source ..
/errhandle
/errcatch-function
23 source ..
/errhandle
/bash-trace-function
27 ## begin arg parsing ##
29 nn
=$2 # network namespace / namespace name
32 ## begin sanity checking ##
35 if ! type -p ip
&>/dev
/null
; then
36 echo "please install the iproute2 package"
39 if ! type -p iptables
&>/dev
/null
; then
40 echo "please install the iptables package"
43 if $install_error; then
47 ## end sanity checking ##
55 target
=/run
/netns
/default
56 if [[ ! -e $target && ! -L $target ]]; then
58 # make the default network namespace be named
59 ln -s /proc
/1/ns
/net
$target
63 ipd
() { ip
-n default
"$@"; }
64 dexec
() { ip netns
exec default
"$@"; }
66 # note: this script could be easily adapted to create a
67 # netns instead of using the systemd created one.
69 # ip -n NAME link set dev lo up
71 # random note, ip netns exec creates a mount namespace and
72 # remaps /etc to /etc/netns/NAME.
74 # head -n1 is defensive. I don't know if it's possible to have more
75 # than one default route.
76 gateway_if
=$
(ipd route list exact
0/0 |
head -n1|
sed -r 's/.*\s(\S+)\s*$/\1/')
77 nat
() { dexec iptables
-t nat
$1 POSTROUTING
-o $gateway_if -j MASQUERADE \
78 -m comment
--comment "systemd network namespace nat"; }
83 ips
="$(ipd addr show | awk '$1 == "inet
" {print $2}')"
84 for ((i
=0; i
<= 254; i
++)); do
86 if printf "%s\n" "$ips" |
grep "^${network//./\\.}"; then
97 mkdir
-p /root
/mount_namespaces
98 if ! mountpoint
/root
/mount_namespaces
>/dev
/null
; then
99 mount
--bind /root
/mount_namespaces
/root
/mount_namespaces
100 mount
--make-private /root
/mount_namespaces
102 if [[ ! -e /root
/mount_namespaces
/$nn ]]; then
103 touch /root
/mount_namespaces
/$nn
105 if ! mountpoint
/root
/mount_namespaces
/$nn >/dev
/null
; then
106 unshare
--mount=/root
/mount_namespaces
/$nn
113 echo "$0: error: no open network found"
117 echo 1 | dexec
dd of
=/proc
/sys
/net
/ipv
4/ip_forward
2>/dev
/null
119 _errcatch_cleanup
=stop
120 ip link add
$v0 type veth peer name
$v1
121 ip link
set $v0 netns default
122 ipd addr add
$network.1/24 dev
$v0
124 nat
-C &>/dev
/null || nat
-A
125 ip addr add
$network.2/24 dev
$v1
127 ip route add default via
$network.1
132 if ipd link list
$v0 &>/dev
/null
; then
133 # this also deletes $v1 and the route we added.
138 if nat
-C &>/dev
/null
; then nat
-D; fi
147 echo "$0: error: unsupported action"