-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtorvirt
executable file
·125 lines (115 loc) · 3.92 KB
/
torvirt
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
#!/bin/sh
set -euo pipefail
PROJECT_NAME="torvirt"
CONTAINER_RT="podman"
IMG_NAME=$PROJECT_NAME
GW_CONTAINER=$PROJECT_NAME
GW_IF="$PROJECT_NAME-gw"
NETWORK=$PROJECT_NAME
GW_DIR="gateway"
NETWORK_FILE="network.xml"
TOR_TRANS_PORT="9040"
TOR_DNS_PORT="5353"
TOR_VIRT_ADDR="10.192.0.0/10"
GW_IP="10.2.2.254/24"
export LIBVIRT_DEFAULT_URI=qemu:///system
ERROR_INVALID_ACTION=1
ERROR_CANNOT_PRIVESC=2
ERROR_NOT_CONFIGURED=3
ERROR_ALREADY_RUNNING=4
print_help() {
echo "Usage: $0 <action>
ACTIONS:
c, configure Install dependencies, configure network and build gateway OCI image
s, start Start the gateway
"
}
exit_with() {
echo "$2" >&2
exit $1
}
virsh_get_field() {
virsh net-info $NETWORK |awk "/^$1:/{print \$2}"
}
if [ "$#" -eq 0 ]; then
print_help
exit
fi
case $1 in
"s" | "start")
# find a way to elevate privileges
if [ "$(id -u)" -eq 0 ]; then
AS_ROOT() { "$@"; }
elif command -v doas >/dev/null; then
AS_ROOT() { doas "$@"; }
elif command -v sudo >/dev/null; then
AS_ROOT() { sudo "$@"; }
elif command -v pkexec >/dev/null; then
AS_ROOT() { pkexec "$@"; }
elif command -v su >/dev/null; then
AS_ROOT() { su root -c "$@"; }
else
exit_with $ERROR_CANNOT_PRIVESC "Error: $PROJECT_NAME needs root access, but neither doas, sudo, pkexec nor su could be found."
fi
# check whether network and gateway have been configured
if ! virsh net-list --all | grep -q $NETWORK; then
exit_with $ERROR_NOT_CONFIGURED "Error: network $NETWORK not found. Did you run \"$PROJECT_NAME configure\" ?"
fi
output=$($CONTAINER_RT image ls -q -f reference=$IMG_NAME)
if [ -z "$output" ]; then
exit_with $ERROR_NOT_CONFIGURED "Error: OCI image $IMG_NAME not found. Did you run \"$PROJECT_NAME configure\" first ?"
fi
output=$($CONTAINER_RT ps -q -f name=$GW_CONTAINER)
if [ "$output" ]; then
exit_with $ERROR_ALREADY_RUNNING "Error: conatiner $GW_CONTAINER is already running"
fi
output=$($CONTAINER_RT ps -aq -f status=exited -f name=$GW_CONTAINER)
if [ "$output" ]; then
$CONTAINER_RT rm $GW_CONTAINER
fi
# start $NETWORK
network_started=$(virsh_get_field "Active")
if [ "$network_started" = "no" ]; then
virsh net-start $NETWORK
fi
# create gateway macvlan interface
AS_ROOT ip link add $GW_IF link "$(virsh_get_field "Bridge")" type macvlan mode private
# start gateway on wait.sh
$CONTAINER_RT run --rm -itd --cap-drop=ALL --security-opt=no-new-privileges --name $GW_CONTAINER $IMG_NAME >/dev/null
pid=$($CONTAINER_RT inspect -f '{{.State.Pid}}' $GW_CONTAINER)
# setup gateway networing inside $NETWORK
AS_ROOT ip link set netns $pid dev $GW_IF
AS_ROOT nsenter -t $pid -n ip link set $GW_IF up
AS_ROOT nsenter -t $pid -n ip addr add $GW_IP dev $GW_IF
# allow *.onion
AS_ROOT nsenter -t $pid -n iptables -t nat -A PREROUTING -i $GW_IF -p tcp -d $TOR_VIRT_ADDR --syn -j REDIRECT --to-ports $TOR_TRANS_PORT
# redirect DNS to tor
AS_ROOT nsenter -t $pid -n iptables -t nat -A PREROUTING -i $GW_IF -p udp --dport 53 -j REDIRECT --to-ports $TOR_DNS_PORT
AS_ROOT nsenter -t $pid -n iptables -t nat -A PREROUTING -i $GW_IF -p udp --dport $TOR_DNS_PORT -j REDIRECT --to-ports $TOR_DNS_PORT
# redirect TCP to tor
AS_ROOT nsenter -t $pid -n iptables -t nat -A PREROUTING -i $GW_IF -p tcp --syn -j REDIRECT --to-ports $TOR_TRANS_PORT
# disable IP forwarding to prevent leaking unhandled traffic
AS_ROOT nsenter -t $pid -n iptables -P FORWARD DROP
AS_ROOT nsenter -t $pid -n sysctl -q net.ipv4.ip_forward=0
# start tor
$CONTAINER_RT kill -s USR1 $GW_CONTAINER >/dev/null
$CONTAINER_RT attach $GW_CONTAINER
;;
"c" | "configure")
if virsh net-info $NETWORK >/dev/null 2>/dev/null; then
echo "Libvirt network $NETWORK already exists."
else
virsh net-define $NETWORK_FILE
fi
output=$($CONTAINER_RT image ls -q -f reference=$IMG_NAME)
if [ "$output" ]; then
echo "OCI image $IMG_NAME already exists"
else
cd $GW_DIR && $CONTAINER_RT build -t $IMG_NAME .
fi
;;
*)
print_help
exit_with $ERROR_INVALID_ACTION "Unkown action: $1"
;;
esac