diff options
Diffstat (limited to 'scripts/netjail/netjail_core.sh')
-rwxr-xr-x | scripts/netjail/netjail_core.sh | 265 |
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 | |||
4 | INTERFACE_FORMAT_STRING="%s%06x-%06x" | ||
5 | PREPREFIX=if | ||
6 | PREFIX=${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 | |||
12 | export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" | ||
13 | |||
14 | export RESULT= | ||
15 | export NAMESPACE_NUM=0 | ||
16 | export INTERFACE_NUM=0 | ||
17 | |||
18 | netjail_next_namespace() { | ||
19 | local NUM=$NAMESPACE_NUM | ||
20 | NAMESPACE_NUM=$(($NAMESPACE_NUM + 1)) | ||
21 | RESULT=$NUM | ||
22 | } | ||
23 | |||
24 | netjail_next_interface() { | ||
25 | local NUM=$INTERFACE_NUM | ||
26 | INTERFACE_NUM=$(($INTERFACE_NUM + 1)) | ||
27 | RESULT=$NUM | ||
28 | } | ||
29 | |||
30 | netjail_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 | |||
49 | netjail_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 | |||
66 | netjail_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 | |||
81 | netjail_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 | |||
94 | netjail_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 | |||
105 | netjail_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 | |||
113 | netjail_bridge_clear() { | ||
114 | local BRIDGE=$1 | ||
115 | |||
116 | ip link delete $BRIDGE | ||
117 | } | ||
118 | |||
119 | netjail_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 | |||
129 | netjail_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 | |||
137 | netjail_node_clear() { | ||
138 | local NODE=$1 | ||
139 | |||
140 | ip netns delete $NODE | ||
141 | } | ||
142 | |||
143 | netjail_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 | |||
170 | netjail_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 | |||
181 | netjail_node_unlink_bridge() { | ||
182 | local LINK_BR=$1 | ||
183 | |||
184 | ip link delete $LINK_BR | ||
185 | } | ||
186 | |||
187 | netjail_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 | |||
199 | netjail_node_add_default() { | ||
200 | local NODE=$1 | ||
201 | local ADDRESS=$2 | ||
202 | |||
203 | ip -n $NODE route add default via $ADDRESS | ||
204 | } | ||
205 | |||
206 | netjail_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 | |||
216 | netjail_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 | |||
224 | netjail_node_exec_without_fds_and_sudo() { | ||
225 | NODE=$1 | ||
226 | shift 1 | ||
227 | |||
228 | ip netns exec $NODE $@ | ||
229 | } | ||
230 | |||
231 | netjail_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 | |||
246 | netjail_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 | |||
256 | netjail_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 | |||