forked from orjail/orjail
-
Notifications
You must be signed in to change notification settings - Fork 0
/
orjail
executable file
·485 lines (409 loc) · 12.8 KB
/
orjail
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
#!/bin/bash
REALPATH=`realpath $0`
REALPATH=`dirname $REALPATH`
DEFAULTNAME=orjail
NAME=$DEFAULTNAME
USERNAME=${SUDO_USER:-$(whoami)}
USEFIREJAIL=n
VERBOSE=
TORBIN=
KEEP=
HIDDENSERVICE=
HIDDENSERVICEDIR=
IPHOSTDEFAULT=10.200.1.1
IPHOST=$IPHOSTDEFAULT
IPNETNSDEFAULT=10.200.1.2
IPNETNS=$IPNETNSDEFAULT
NETMASKDEFAULT=24
NETMASK=$NETMASKDEFAULT
SUDOBIN="$(which sudo)"
FORCEYES=n
# Functions
# ~~~~~~~~~
print_real() {
if [ "$VERBOSE" != y ]; then
return
fi
if [ -t 1 ]; then
NCOLORS=$(tput colors)
if test -n "$NCOLORS" && test $NCOLORS -ge 8; then
NORMAL="$(tput sgr0)"
RED="$(tput setaf 1)"
GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
fi
fi
if [ $2 = 'G' ]; then
echo $1 -e "${GREEN}$3${NORMAL}"
elif [ $2 = 'Y' ]; then
echo $1 -e "${YELLOW}$3${NORMAL}"
elif [ $2 = 'N' ]; then
echo $1 -e "$3"
else
echo $1 -e "${RED}$3${NORMAL}"
fi
}
print() {
print_real '' "$1" "$2"
}
printn() {
print_real "-n" "$1" "$2"
}
printv() {
OLDVERBOSE=$VERBOSE
VERBOSE=y
print_real '' "$1" "$2"
VERBOSE=$OLDVERBOSE
}
printvn() {
OLDVERBOSE=$VERBOSE
VERBOSE=y
print_real "-n" "$1" "$2"
VERBOSE=$OLDVERBOSE
}
# Handler of namespace, tor and resolve file
cleanup() {
# removing the namespace
TORPID=$(cat /tmp/orjail-$NAME/pid)
if [ "$KEEP" = y ]; then
print G " * Keep Tor process $TORPID running"
print G " * Keep active the namespace $NAME"
else
print G " * Remove Tor temporary configuration"
rm $TORCONFIGFILE
print G " * Killing Tor process $TORPID"
kill -9 $TORPID &> /dev/null
wait $! &> /dev/null
print G " * Killed $TORPID"
print G " * Remove Tor DataDirectory: /tmp/orjail-$NAME"
rm -fr /tmp/orjail-$NAME
print G " * Remove in-$NAME network interface"
ip link del in-$NAME
print G " * Delete network namespace $NAME"
ip netns delete $NAME
print G " * Cleaning up iptables rules..."
iptables -t nat -D PREROUTING -i in-$NAME -p udp -d $IPHOST --dport 53 -j DNAT \
--to-destination $IPHOST:5354
iptables -t nat -D PREROUTING -i in-$NAME -p tcp --syn -j DNAT \
--to-destination $IPHOST:9040
iptables -D OUTPUT -o in-$NAME -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -D INPUT -i in-$NAME -j DROP
if [[ $HIDDENSERVICE = y ]]; then
iptables -D INPUT -i in-$NAME -p tcp --destination $IPNETNS --dport $HSERVICEPORT -j ACCEPT
iptables -D INPUT -i in-$NAME -p tcp --source $IPNETNS --sport $HSERVICEPORT -j ACCEPT
fi
iptables -D INPUT -i in-$NAME -p udp --destination $IPHOST --dport 5354 -j ACCEPT
iptables -D INPUT -i in-$NAME -p tcp --destination $IPHOST --dport 9040 -j ACCEPT
fi
print G " * Remove the temporary resolve file $RESOLVEFILE..."
rm "$RESOLVEFILE"
}
# Handler of breakout signals
interrupted() {
printv R " * Received breakout signal"
cleanup
exit 1
}
error() {
printv R "$1"
}
die() {
error "$1"
exit 1
}
help_and_exit() {
VERBOSE=y
printn N "Usage: "
printn Y "$DEFAULTNAME"
print G " <options> [command <arguments>...]"
print N "Options:"
print N " -h, --help It shows this menu."
print N " -u, --user <user> Execute the command with this user permission. By default '$USERNAME'."
print N " -n, --name <name> Set a custom namespace name. By default '$DEFAULTNAME'."
print N " -v, --verbose Verbose mode."
print N " -k, --keep Don't delete namespace and don't kill tor after the execution."
print N " -f, --firejail Use firejail as a security container ($SUDOBIN orjail -f pidgin)."
print N " -y, --yes Answer all questions with "y" (orjail -y pidgin)."
print N " -H, --hidden <port>"
print N " Enable Tor as an hidden service forwarding request from/to specified port."
print N " -d, --hiddendir <dir>"
print N " Specify where to search for hidden service 'hostname' and 'private_key'."
print N " -s, --shell Execute a shell."
print N " -r, --routing <ip_host> <ip_ns> <netmask>"
print N " Set custom IPs. By default $IPHOSTDEFAULT/$IPNETNSDEFAULT/$NETMASKDEFAULT."
exit $1
}
# Inside part
# ~~~~~~~~~~~
# This script calls itself. yeah \o/ This part is executed only inside the
# namespace. The arguments are:
# --inside <username> <resolvefile> <silence> <command> <arguments...>
if [ "$1" = "--inside" ]; then
REALPATH=`realpath $0`
REALPATH=`dirname $REALPATH`
shift
USERNAME="$1"
shift
RESOLVEFILE="$1"
shift
VERBOSE="$1"
shift
print G " * Replacing resolv.conf..."
mount --bind -o users $RESOLVEFILE /etc/resolv.conf || \
error "Failed to mount /etc/resolv.conf."
print G " * Executing..."
if [ "$SUDOBIN" ]; then
$SUDOBIN -u $USERNAME "$@"
else
su $USERNAME -c "$*"
fi || error "Execution failed."
exit
fi
# The tool
# ~~~~~~~~
# Call cleanup on ctrl-c (SIGINT) and more breakout signals
trap interrupted HUP INT QUIT TERM ABRT
# Arguments check
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
# Replacing the name
-n|--name)
NAME="$2"
shift
if [ "$NAME" = "" ]; then
printv R "$key requires an argument."
exit 1
fi
;;
# Username
-u|--username)
USERNAME="$2"
shift
if [ "$USERNAME" = "" ]; then
printv R "$key requires an argument."
exit 1
fi
;;
-v|--verbose)
VERBOSE=y
;;
-k|--keep)
KEEP=y
;;
-H|--hidden)
HIDDENSERVICE=y
HSERVICEPORT="$2"
shift
if [ "$HSERVICEPORT" = "" ]; then
printv R "$key requires an argument."
exit 1
fi
;;
-d|--hiddendir)
HIDDENSERVICEDIR="$2"
shift
if [ "$HIDDENSERVICEDIR" = "" ]; then
printv R "$key requires an argument."
exit 1
fi
;;
-r|--routing)
IPHOST="$2"
shift
IPNETNS="$2"
shift
NETMASK="$2"
shift
if [ "$IPHOST" = "" ] ||
[ "$IPNETNS" = "" ] ||
[ "$NETMASK" = "" ]; then
printv R "$key requires 3 arguments."
exit 1
fi
;;
-f|--firejail)
USEFIREJAIL=y
;;
-y|--yes)
FORCEYES=y
;;
-s|--shell)
set -- $@ "$SHELL"
;;
# Help menu
-h|--help)
help_and_exit 0
;;
# End my options
--)
shift
break
;;
# Illegal options
-*)
printv R "$key unknown option."
exit 1
;;
# The rest
*)
break
;;
esac
shift
done
if [[ $EUID -ne 0 ]]; then
printv R "$DEFAULTNAME must be run as root."
exit 1
fi
TORBIN=$(type -P tor 2>/dev/null)
if [[ $? -ne 0 ]]; then
print R "Can't locate tor executable.";
exit 1
fi
# No arguments, no party
if [ "$1" = "" ]; then
help_and_exit 1
fi
# Check linux kernel
if [ "$(uname)" != Linux ]; then
printv R "No Linux no party"
exit 1
fi
FIREJAILBIN=
if [ $USEFIREJAIL = y ]; then
FIREJAILBIN=firejail
fi
err=0
for cmd in ip iptables tor $FIREJAILBIN ${SUDOBIN:-su}; do
if ! [ file = "$(type -t $cmd 2>/dev/null)" ]; then
printv R "$cmd isn't a command file"
err=1
fi
done
! [ 0 = $err ] && exit $err
# check if network namespace already exists
ip netns list | grep -e \\b$NAME\\b &> /dev/null
if [ $? -ne 0 ]; then
if [ $FORCEYES == n ]; then
printv G "It seems that you don't have the namespace $NAME."
printvn Y "Do you want to create it? [y/n] "
read CREATE
else
CREATE=y
fi
if [ "$CREATE" != y ] && [ "$CREATE" != Y ]; then
print G "Ok. Bye!"
exit 0
fi
print G " * Creating a $NAME namespace..."
# add network namespace
ip netns add $NAME || die "Failed to add a new namespace"
# Create veth link.
print G " * Creating a veth link..."
ip link add in-$NAME type veth peer name out-$NAME || \
die "Failed to add a veth interface"
# Add out to NS.
print G " * Sharing the veth interface..."
ip link set out-$NAME netns $NAME || \
die "Failed to assign veth interface to the namespace"
## setup ip address of host interface
print G " * Setting up IP address of host interface..."
ip addr add $IPHOST/$NETMASK dev in-$NAME || \
die "Failed to assign veth interface to the host"
ip link set in-$NAME up || die "Failed to set up the veth interface"
# setup ip address of peer
print G " * Setting up IP address of peer interface..."
ip netns exec $NAME ip addr add $IPNETNS/$NETMASK dev out-$NAME || \
die "Failed to assign an IP to the veth interface"
ip netns exec $NAME ip link set out-$NAME up || \
die "Failed to assign an IP to the veth interface"
# default route
print G " * Default routing up..."
ip netns exec $NAME ip route add default via $IPHOST || \
die "Failed to set up the network routing"
# resolve with tor
print G " * Resolving via Tor"
iptables -t nat -A PREROUTING -i in-$NAME -p udp -d $IPHOST --dport 53 -j DNAT \
--to-destination $IPHOST:5354 || \
die "Failed to configure iptable for routing the Tor DNS lookup"
# traffic througth tor
print G " * Traffic via Tor..."
iptables -t nat -A PREROUTING -i in-$NAME -p tcp --syn -j DNAT \
--to-destination $IPHOST:9040 || \
die "Failed to configure iptable for routing the network traffic"
iptables -A OUTPUT -m state -o in-$NAME --state ESTABLISHED,RELATED -j ACCEPT || \
die "Failed to configure the iptable for accepting connection"
# REJECT all traffic coming from orjail
# this is needed to avoid reaching other interfaces
iptables -I INPUT -i in-$NAME -p udp --destination $IPHOST --dport 5354 -j ACCEPT &&
iptables -I INPUT -i in-$NAME -p tcp --destination $IPHOST --dport 9040 -j ACCEPT &&
if [[ $HIDDENSERVICE = y ]]; then
iptables -I INPUT -i in-$NAME -p tcp --source $IPNETNS --sport $HSERVICEPORT -j ACCEPT &&
iptables -I INPUT -i in-$NAME -p tcp --destination $IPNETNS --dport $HSERVICEPORT -j ACCEPT
fi &&
# while we inserted the rules above, the DROP rule must be appended instead
iptables -A INPUT -i in-$NAME -j DROP || \
die "Failed to configure iptables for rejecting traffic from orjail"
# executing tor
print G " * Creating the Tor configuration file..."
# automatically detect tor version and use appropriate syntax
TORVERSION="$($TORBIN --version|egrep -o ' ([0-9.]+)'|xargs)"
print G " * Tor version is $TORVERSION"
TORCONFIGFILE=$(mktemp /tmp/torXXXXXX)
chown $USERNAME $TORCONFIGFILE || \
die "Failed to change owner of the Tor configuration file $TORCONFIGFILE"
echo "DataDirectory /tmp/orjail-$NAME" > $TORCONFIGFILE &&
echo "AutomapHostsSuffixes .onion,.exit" >> $TORCONFIGFILE &&
echo "AutomapHostsOnResolve 1" >> $TORCONFIGFILE &&
echo "PidFile /tmp/orjail-$NAME/pid" >> $TORCONFIGFILE &&
echo "User $USERNAME" >> $TORCONFIGFILE &&
if [[ $HIDDENSERVICE = y ]]; then
if [[ $HIDDENSERVICEDIR ]]; then
echo "HiddenServiceDir $(realpath $HIDDENSERVICEDIR)" >> $TORCONFIGFILE
else
echo "HiddenServiceDir /tmp/orjail-$NAME" >> $TORCONFIGFILE
fi &&
echo "HiddenServicePort $HSERVICEPORT $IPNETNS:$HSERVICEPORT" >> $TORCONFIGFILE
fi &&
# because some options were deprecated in 0.2.3+
if [[ "$TORVERSION" > "0.2.3" ]]; then
echo "VirtualAddrNetworkIPv4 $IPNETNS/16" >> $TORCONFIGFILE &&
echo "TransPort $IPHOST:9040" >> $TORCONFIGFILE &&
echo "DNSPort $IPHOST:5354" >> $TORCONFIGFILE
else
echo "VirtualAddrNetwork $IPNETNS/16" >> $TORCONFIGFILE &&
echo "TransListenAddress $IPHOST" >> $TORCONFIGFILE &&
echo "TransPort 9040" >> $TORCONFIGFILE &&
echo "DNSListenAddress $IPHOST" >> $TORCONFIGFILE &&
echo "DNSPort 5354" >> $TORCONFIGFILE
fi &&
echo "SOCKSPort 0" >> $TORCONFIGFILE || \
die "Failed to write to the Tor configuration file $TORCONFIGFILE"
# executing tor
print G " * Executing Tor..."
$TORBIN --quiet -f $TORCONFIGFILE &> /dev/null &
else
print Y "$NAME network namespace already exists!"
KEEP=y
fi
RESOLVEFILE=$(mktemp /tmp/resolveXXXXXX)
print G " * Creating a temporary /etc/resolv.conf ($RESOLVEFILE)..."
echo "nameserver $IPHOST" > $RESOLVEFILE || die "Failed to create $RESOLVEFILE"
chmod a+r $RESOLVEFILE || die "Failed to change permissions to $RESOLVEFILE"
# use firejail as security container
if [ $USEFIREJAIL = y ]; then
if [ "$SUDOBIN" ]; then
$SUDOBIN -u $USERNAME $FIREJAILBIN --dns=$IPHOST --netns=$NAME "$@"
else
su $USERNAME -c "$FIREJAILBIN --dns=$IPHOST --netns=$NAME $*"
fi
else #or without
ip netns exec $NAME \
unshare --ipc --fork --pid --mount --mount-proc \
"$0" --inside "$USERNAME" "$RESOLVEFILE" "$VERBOSE" "$@" || \
die "Failed to execute the inside part of this script"
fi
# clean some shit
cleanup
# All done!