2023-05-27 15:14:02 +02:00
|
|
|
#!/bin/sh
|
2023-05-25 22:12:53 +02:00
|
|
|
|
|
|
|
set -e
|
|
|
|
|
2023-05-27 15:14:02 +02:00
|
|
|
PROJECT_NAME="torvirt"
|
|
|
|
CONTAINER_RT="podman"
|
|
|
|
IMG_NAME=$PROJECT_NAME
|
|
|
|
GW_CONTAINER=$PROJECT_NAME
|
2023-05-28 13:45:45 +02:00
|
|
|
GW_IF="$PROJECT_NAME-gw"
|
|
|
|
NETWORK=$PROJECT_NAME
|
|
|
|
|
2023-05-27 15:14:02 +02:00
|
|
|
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"
|
2023-05-28 13:45:45 +02:00
|
|
|
|
|
|
|
export LIBVIRT_DEFAULT_URI=qemu:///system
|
2023-05-25 22:12:53 +02:00
|
|
|
|
|
|
|
ERROR_INVALID_ACTION=1
|
2023-05-27 15:14:02 +02:00
|
|
|
ERROR_CANNOT_PRIVESC=2
|
2023-05-25 22:12:53 +02:00
|
|
|
ERROR_NOT_CONFIGURED=3
|
|
|
|
ERROR_ALREADY_RUNNING=4
|
|
|
|
|
|
|
|
print_help() {
|
|
|
|
echo -e "Usage: $0 <action>
|
|
|
|
|
|
|
|
ACTIONS:
|
2023-05-27 15:14:02 +02:00
|
|
|
c, configure Install dependencies, configure network and build gateway OCI image
|
2023-05-25 22:12:53 +02:00
|
|
|
s, start Start the gateway
|
|
|
|
"
|
|
|
|
}
|
|
|
|
|
|
|
|
exit_with() {
|
|
|
|
echo $2 >&2
|
|
|
|
exit $1
|
|
|
|
}
|
|
|
|
|
|
|
|
virsh_get_field() {
|
2023-05-27 15:14:02 +02:00
|
|
|
virsh net-info $NETWORK |awk "/^$1:/{print \$2}"
|
2023-05-25 22:12:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if [ "$#" -eq 0 ]; then
|
|
|
|
print_help
|
|
|
|
exit
|
|
|
|
fi
|
|
|
|
case $1 in
|
|
|
|
"s" | "start")
|
2023-05-27 15:14:02 +02:00
|
|
|
# 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
|
2023-05-25 22:12:53 +02:00
|
|
|
# check whether network and gateway have been configured
|
2023-05-27 15:14:02 +02:00
|
|
|
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\" ?"
|
2023-05-25 22:12:53 +02:00
|
|
|
fi
|
2023-05-27 15:14:02 +02:00
|
|
|
output=$($CONTAINER_RT image ls -q -f reference=$IMG_NAME)
|
2023-05-25 22:12:53 +02:00
|
|
|
if [ -z "$output" ]; then
|
2023-05-27 15:14:02 +02:00
|
|
|
exit_with $ERROR_NOT_CONFIGURED "Error: OCI image $IMG_NAME not found. Did you run \"$PROJECT_NAME configure\" first ?"
|
2023-05-25 22:12:53 +02:00
|
|
|
fi
|
2023-05-27 15:14:02 +02:00
|
|
|
output=$($CONTAINER_RT ps -q -f name=$GW_CONTAINER)
|
2023-05-25 22:12:53 +02:00
|
|
|
if [ "$output" ]; then
|
2023-05-27 15:14:02 +02:00
|
|
|
exit_with $ERROR_ALREADY_RUNNING "Error: conatiner $GW_CONTAINER is already running"
|
2023-05-25 22:12:53 +02:00
|
|
|
fi
|
2023-05-27 15:14:02 +02:00
|
|
|
output=$($CONTAINER_RT ps -aq -f status=exited -f name=$GW_CONTAINER)
|
2023-05-25 22:12:53 +02:00
|
|
|
if [ "$output" ]; then
|
2023-05-27 15:14:02 +02:00
|
|
|
$CONTAINER_RT rm $GW_CONTAINER
|
2023-05-25 22:12:53 +02:00
|
|
|
fi
|
2023-05-27 15:14:02 +02:00
|
|
|
# start $NETWORK
|
2023-05-25 22:12:53 +02:00
|
|
|
network_started=$(virsh_get_field "Active")
|
|
|
|
if [ $network_started = "no" ]; then
|
2023-05-27 15:14:02 +02:00
|
|
|
virsh net-start $NETWORK
|
2023-05-25 22:12:53 +02:00
|
|
|
fi
|
2023-05-28 13:45:45 +02:00
|
|
|
# create gateway macvlan interface
|
|
|
|
AS_ROOT ip link add $GW_IF link $(virsh_get_field "Bridge") type macvlan mode private
|
2023-05-25 22:12:53 +02:00
|
|
|
# start gateway on wait.sh
|
2023-05-27 15:14:02 +02:00
|
|
|
$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
|
2023-05-28 13:45:45 +02:00
|
|
|
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
|
2023-05-25 22:12:53 +02:00
|
|
|
# allow *.onion
|
2023-05-28 13:45:45 +02:00
|
|
|
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
|
2023-05-25 22:12:53 +02:00
|
|
|
# redirect DNS to tor
|
2023-05-28 13:45:45 +02:00
|
|
|
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
|
2023-05-25 22:12:53 +02:00
|
|
|
# redirect TCP to tor
|
2023-05-28 13:45:45 +02:00
|
|
|
AS_ROOT nsenter -t $pid -n iptables -t nat -A PREROUTING -i $GW_IF -p tcp --syn -j REDIRECT --to-ports $TOR_TRANS_PORT
|
2023-05-25 22:12:53 +02:00
|
|
|
# start tor
|
2023-05-27 15:14:02 +02:00
|
|
|
$CONTAINER_RT kill -s USR1 $GW_CONTAINER >/dev/null
|
|
|
|
$CONTAINER_RT attach $GW_CONTAINER
|
2023-05-25 22:12:53 +02:00
|
|
|
;;
|
|
|
|
"c" | "configure")
|
2023-05-27 15:14:02 +02:00
|
|
|
if virsh net-info $NETWORK >/dev/null 2>/dev/null; then
|
|
|
|
echo "Libvirt network $NETWORK already exists."
|
|
|
|
else
|
|
|
|
virsh net-define $NETWORK_FILE
|
2023-05-25 22:12:53 +02:00
|
|
|
fi
|
2023-05-27 15:14:02 +02:00
|
|
|
output=$($CONTAINER_RT image ls -q -f reference=$IMG_NAME)
|
2023-05-25 22:12:53 +02:00
|
|
|
if [ "$output" ]; then
|
2023-05-27 15:14:02 +02:00
|
|
|
echo "OCI image $IMG_NAME already exists"
|
|
|
|
else
|
|
|
|
cd $GW_DIR && $CONTAINER_RT build -t $IMG_NAME .
|
2023-05-25 22:12:53 +02:00
|
|
|
fi
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
print_help
|
|
|
|
exit_with $ERROR_INVALID_ACTION "Unkown action: $1"
|
|
|
|
;;
|
|
|
|
esac
|