TorVirt/torvirt

123 lines
3.7 KiB
Bash
Executable File

#!/bin/sh
set -e
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 -e "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 [ -z "$(virsh net-list --all | grep $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
# 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