aboutsummaryrefslogtreecommitdiff
path: root/scripts/netjail/netjail_core.sh
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/netjail/netjail_core.sh')
-rwxr-xr-xscripts/netjail/netjail_core.sh265
1 files changed, 265 insertions, 0 deletions
diff --git a/scripts/netjail/netjail_core.sh b/scripts/netjail/netjail_core.sh
new file mode 100755
index 000000000..cb2a271b8
--- /dev/null
+++ b/scripts/netjail/netjail_core.sh
@@ -0,0 +1,265 @@
1#!/bin/bash
2#
3
4INTERFACE_FORMAT_STRING="%s%06x-%06x"
5PREPREFIX=if
6PREFIX=${PPID:?must run from a parent process}
7
8# running with `sudo` is required to be
9# able running the actual commands as the
10# original user.
11
12export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
13
14export RESULT=
15export NAMESPACE_NUM=0
16export INTERFACE_NUM=0
17
18netjail_next_namespace() {
19 local NUM=$NAMESPACE_NUM
20 NAMESPACE_NUM=$(($NAMESPACE_NUM + 1))
21 RESULT=$NUM
22}
23
24netjail_next_interface() {
25 local NUM=$INTERFACE_NUM
26 INTERFACE_NUM=$(($INTERFACE_NUM + 1))
27 RESULT=$NUM
28}
29
30netjail_opt() {
31 local OPT=$1
32 shift 1
33
34 INDEX=1
35
36 while [ $# -gt 0 ]; do
37 if [ "$1" = "$OPT" ]; then
38 RESULT=$INDEX
39 return
40 fi
41
42 INDEX=$(($INDEX + 1))
43 shift 1
44 done
45
46 RESULT=0
47}
48
49netjail_opts() {
50 local OPT=$1
51 local DEF=$2
52 shift 2
53
54 while [ $# -gt 0 ]; do
55 if [ "$1" = "$OPT" ]; then
56 printf "$2"
57 return
58 fi
59
60 shift 1
61 done
62
63 RESULT="$DEF"
64}
65
66netjail_check() {
67 local NODE_COUNT=$1
68 local FD_COUNT=$(($(ls /proc/self/fd | wc -w) - 4))
69
70 # quit if `$FD_COUNT < ($LOCAL_M * $GLOBAL_N * 2)`:
71 # the script also requires `sudo -C ($FD_COUNT + 4)`
72 # so you need 'Defaults closefrom_override' in the
73 # sudoers file.
74
75 if [ $FD_COUNT -lt $(($NODE_COUNT * 2)) ]; then
76 echo "File descriptors do not match requirements!" >&2
77 exit 1
78 fi
79}
80
81netjail_check_bin() {
82 local PROGRAM=$1
83 local MATCH=$(ls $(echo $PATH | tr ":" "\n") | grep "^$PROGRAM\$" | tr "\n" " " | awk '{ print $1 }')
84
85 # quit if the required binary $PROGRAM can not be
86 # found in the used $PATH.
87
88 if [ "$MATCH" != "$PROGRAM" ]; then
89 echo "Required binary not found: $PROGRAM" >&2
90 exit 1
91 fi
92}
93
94netjail_bridge() {
95 netjail_next_interface
96 local NUM=$RESULT
97 local BRIDGE=$(printf $INTERFACE_FORMAT_STRING $PREPREFIX $PREFIX $NUM)
98
99 ip link add $BRIDGE type bridge
100 ip link set dev $BRIDGE up
101
102 RESULT=$BRIDGE
103}
104
105netjail_bridge_name() {
106 netjail_next_interface
107 local NUM=$RESULT
108 local BRIDGE=$(printf $INTERFACE_FORMAT_STRING $PREPREFIX $PREFIX $NUM)
109
110 RESULT=$BRIDGE
111}
112
113netjail_bridge_clear() {
114 local BRIDGE=$1
115
116 ip link delete $BRIDGE
117}
118
119netjail_node() {
120 netjail_next_namespace
121 local NUM=$RESULT
122 local NODE=$(printf $INTERFACE_FORMAT_STRING $PREPREFIX $PREFIX $NUM)
123
124 ip netns add $NODE
125
126 RESULT=$NODE
127}
128
129netjail_node_name() {
130 netjail_next_namespace
131 local NUM=$RESULT
132 local NODE=$(printf $INTERFACE_FORMAT_STRING $PREPREFIX $PREFIX $NUM)
133
134 RESULT=$NODE
135}
136
137netjail_node_clear() {
138 local NODE=$1
139
140 ip netns delete $NODE
141}
142
143netjail_node_link_bridge() {
144 local NODE=$1
145 local BRIDGE=$2
146 local ADDRESS=$3
147 local MASK=$4
148
149 netjail_next_interface
150 local NUM_IF=$RESULT
151 netjail_next_interface
152 local NUM_BR=$RESULT
153
154 local LINK_IF=$(printf $INTERFACE_FORMAT_STRING $PREPREFIX $PREFIX $NUM_IF)
155 local LINK_BR=$(printf $INTERFACE_FORMAT_STRING $PREPREFIX $PREFIX $NUM_BR)
156
157 ip link add $LINK_IF type veth peer name $LINK_BR
158 ip link set $LINK_IF netns $NODE
159 ip link set $LINK_BR master $BRIDGE
160
161 ip -n $NODE addr add "$ADDRESS/$MASK" broadcast + dev $LINK_IF
162 ip -n $NODE link set $LINK_IF up
163 ip -n $NODE link set up dev lo
164
165 ip link set $LINK_BR up
166
167 RESULT=$LINK_IF
168}
169
170netjail_node_link_bridge_name() {
171
172 netjail_next_interface
173 netjail_next_interface
174 local NUM_BR=$RESULT
175
176 local LINK_BR=$(printf $INTERFACE_FORMAT_STRING $PREPREFIX $PREFIX $NUM_BR)
177
178 RESULT=$LINK_BR
179}
180
181netjail_node_unlink_bridge() {
182 local LINK_BR=$1
183
184 ip link delete $LINK_BR
185}
186
187netjail_node_add_nat() {
188 local NODE=$1
189 local ADDRESS=$2
190 local MASK=$3
191
192 ip netns exec $NODE sysctl -w net.ipv4.ip_forward=1
193 ip netns exec $NODE nft add table nat
194 ip netns exec $NODE nft add chain nat postrouting { type nat hook postrouting priority 0 \; }
195 ip netns exec $NODE nft add rule ip nat postrouting ip saddr "$ADDRESS/$MASK" counter masquerade
196 # ip netns exec $NODE iptables -t nat -A POSTROUTING -s "$ADDRESS/$MASK" -j MASQUERADE
197}
198
199netjail_node_add_default() {
200 local NODE=$1
201 local ADDRESS=$2
202
203 ip -n $NODE route add default via $ADDRESS
204}
205
206netjail_node_exec() {
207 JAILOR=${SUDO_USER:?must run in sudo}
208 local NODE=$1
209 local FD_IN=$2
210 local FD_OUT=$3
211 shift 3
212
213 ip netns exec $NODE sudo -u $JAILOR -- $@ 1>& $FD_OUT 0<& $FD_IN
214}
215
216netjail_node_exec_without_fds() {
217 JAILOR=${SUDO_USER:?must run in sudo}
218 NODE=$1
219 shift 1
220
221 ip netns exec $NODE sudo -u $JAILOR -- $@
222}
223
224netjail_node_exec_without_fds_and_sudo() {
225 NODE=$1
226 shift 1
227
228 ip netns exec $NODE $@
229}
230
231netjail_kill() {
232 local PID=$1
233 local MATCH=$(ps --pid $PID | awk "{ if ( \$1 == $PID ) { print \$1 } }" | wc -l)
234
235 if [ $MATCH -gt 0 ]; then
236 kill -n 19 $PID
237
238 for CHILD in $(ps -o pid,ppid -ax | awk "{ if ( \$2 == $PID ) { print \$1 } }"); do
239 netjail_kill $CHILD
240 done
241
242 kill $PID
243 fi
244}
245
246netjail_killall() {
247 if [ $# -gt 0 ]; then
248 local PIDS=$1
249
250 for PID in $PIDS; do
251 netjail_kill $PID
252 done
253 fi
254}
255
256netjail_waitall() {
257 if [ $# -gt 0 ]; then
258 local PIDS=$1
259
260 for PID in $PIDS; do
261 wait $PID
262 done
263 fi
264}
265