#!/bin/bash

## Copyright (C) 2012 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

#### meta start
#### project Whonix
#### category networking and apps
#### workstation_only yes
#### description
## Generates systemd unit files in
## <code>/lib/systemd/system/anon-ws-disable-stacked-tor_autogen_*</code> which
## listen on common local ports used by popular Tor applications such as Tor
## Browser.
##
## Redirect Whonix-Workstation port <code>9050</code> to Whonix-Gateway port
## <code>9050</code> and so forth.
##
## Create a unix domain socket files such as
## /run/anon-ws-disable-stacked-tor/127.0.0.1_9050.sock and forward those
## to $GATEWAY_IP:9150 etc. See also:
## https://phabricator.whonix.org/T192
##
## system Tor default SocksSocket is /run/tor/socks
## redirect Whonix-Workstation unix domain socket file /run/tor/socks to Whonix-Gateway port 9050
##
## Debian /usr/share/tor/tor-service-defaults-torrc uses '/run/tor/control' Tor ControlSocket
## Redirect Whonix-Workstation unix domain socket file /run/tor/control to Whonix-Gateway port 9051
#### meta end

########
# init #
########

set -e

MYDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

## Change to either system or package source code root folder.
cd "$MYDIR"
cd ..
cd ..
cd ..

#####################
# built-in defaults #
#####################

## Redirect Whonix-Workstation port 9050 to Whonix-Gateway port 9050 and so forth.
file_port_tuples+=" port#9050:9050 " ## system Tor default SocksPort
file_port_tuples+=" port#9150:9150 " ## Tor Browser Bundle default SocksPort
file_port_tuples+=" port#9051:9051 " ## Tor default ControlPort
file_port_tuples+=" port#9151:9051 " ## Tor Browser Bundle default ControlPort
file_port_tuples+=" port#9102:9102 " ## Thunderbird

## Create a unix domain socket files such as
## /run/anon-ws-disable-stacked-tor/127.0.0.1_9050.sock and forward those
## to $GATEWAY_IP:9150 etc. See also:
## https://phabricator.whonix.org/T192
file_port_tuples+=" /run/anon-ws-disable-stacked-tor/127.0.0.1_9050.sock#9050 "
file_port_tuples+=" /run/anon-ws-disable-stacked-tor/127.0.0.1_9150.sock#9150 "
file_port_tuples+=" /run/anon-ws-disable-stacked-tor/127.0.0.1_9051.sock#9051 "
file_port_tuples+=" /run/anon-ws-disable-stacked-tor/127.0.0.1_9151.sock#9051 "

## system Tor default SocksSocket is /run/tor/socks
## redirect Whonix-Workstation unix domain socket file /run/tor/socks to Whonix-Gateway port 9050
file_port_tuples+=" /run/tor/socks#9050 "

## Debian /usr/share/tor/tor-service-defaults-torrc uses '/run/tor/control' Tor ControlSocket
## Redirect Whonix-Workstation unix domain socket file /run/tor/control to Whonix-Gateway port 9051
file_port_tuples+=" /run/tor/control#9051 "

########################
# parse config folders #
########################

## Process configuration folders. Allows overwriting GATEWAY_IP.

shopt -s nullglob
for i in etc/anon-ws-disable-stacked-tor.d/*.conf rw/anon-ws-disable-stacked-tor.d/*.conf /usr/local/etc/anon-ws-disable-stacked-tor.d/*.conf; do
   bash_n_exit_code="0"
   bash_n_output="$(bash -n "$i" 2>&1)" || { bash_n_exit_code="$?" ; true; };
   if [ ! "$bash_n_exit_code" = "0" ]; then
      echo "Invalid config file: $i
bash_n_exit_code: $bash_n_exit_code
bash_n_output:
$bash_n_output" >&2
      exit 1
   fi
   source "$i"
done

#############
# variables #
#############

if [ "$BASH_SOURCE" = "/usr/libexec/anon-ws-disable-stacked-tor/systemd-unit-files-generator" ]; then
   [ -n "$system_run" ] || system_run="true"
   [ -n "$generated_comment" ] || generated_comment="This file was auto generated by $BASH_SOURCE at system runtime."
   if [ "$GATEWAY_IP" = "" ]; then
      ## Provides variable $GATEWAY_IP so it can be used by `source`d config snippets.
      eval $(/usr/libexec/helper-scripts/settings_echo)
   fi
else
   [ -n "$system_run" ] || system_run="false"
   script_name_without_leading_dot="$(echo "$BASH_SOURCE" | str_replace "./" "/")"
   [ -n "$generated_comment" ] || generated_comment="This file was auto generated by $script_name_without_leading_dot at package build time."
   if [ "$GATEWAY_IP" = "" ]; then
      ## IP HARDCODED. Set GATEWAY_IP through a drop-in configuration snippet in /etc/anon-ws-disable-stacked-tor.d configuration folder instead.
      GATEWAY_IP="10.152.152.10"
   fi
fi

#############
# generator #
#############

mkdir -p usr/share/lintian/overrides

## Create lintian override file header.
echo "\
## Copyright (C) 2017 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## $generated_comment

## Dummy script does not need a man page. Original man page still available.
anon-ws-disable-stacked-tor: no-manual-page usr/sbin/tor.anondist

## false positive lintian warning for static systemd unit file
## http://lists.alioth.debian.org/pipermail/pkg-systemd-maintainers/2017-March/014380.html
## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=832771#32" > usr/share/lintian/overrides/anon-ws-disable-stacked-tor

## Delete previously automatically generated systemd unit files by this script.
rm -f lib/systemd/system/anon-ws-disable-stacked-tor_autogen_*

for item in $file_port_tuples ; do
   file_item="${item%#*}"
   port_tuples="${item##*#}"

   source_port="${port_tuples%:*}"
   destination_port="${port_tuples##*:}"

   destination_where="${GATEWAY_IP}:${destination_port}"

   if [ "$file_item" = "port" ]; then
      listen_where="127.0.0.1:$source_port"
      file_name="port_${source_port}"

   else
      listen_where="$file_item"
      file_basename="${file_item##*/}"
      file_name=${file_item//\//\_}
   fi

   echo "\
## Copyright (C) 2018 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## $generated_comment

[Unit]
Description=redirect $listen_where to Whonix-Gateway port ${destination_port}
Documentation=https://www.whonix.org/wiki/Dev/anon-ws-disable-stacked-tor
ConditionPathExists=!/run/qubes/this-is-templatevm

[Socket]
ListenStream=$listen_where
SocketUser=debian-tor
SocketMode=666
DirectoryMode=2755

[Install]
WantedBy=sockets.target" > "./lib/systemd/system/anon-ws-disable-stacked-tor_autogen_${file_name}.socket"

   echo "\
## Copyright (C) 2018 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## $generated_comment

[Unit]
## IP HARDCODED. See next comment below.
Description=redirect $listen_where to Whonix-Gateway port ${destination_port}
Documentation=https://www.whonix.org/wiki/Dev/anon-ws-disable-stacked-tor
ConditionPathExists=!/run/qubes/this-is-templatevm
## IP HARDCODED. See next comment below.
After=anon-ws-disable-stacked-tor_autogen_${file_name}.socket
Requires=anon-ws-disable-stacked-tor_autogen_${file_name}.socket

[Service]
## IP HARDCODED. If you want to change IP, set variable GATEWAY_IP through a
## drop-in configuration snippet in /etc/anon-ws-disable-stacked-tor.d
## configuration folder instead.
## Then run the systemd-socket-proxyd systemd-unit-files-generator.
#sudo /usr/libexec/anon-ws-disable-stacked-tor/systemd-unit-files-generator
## See Documentation:
## https://www.whonix.org/wiki/Redirect_Whonix-Workstation_Ports_or_Unix_Domain_Socket_Files_to_Whonix-Gateway
ExecStart=/lib/systemd/systemd-socket-proxyd $destination_where
PrivateTmp=yes" > "./lib/systemd/system/anon-ws-disable-stacked-tor_autogen_${file_name}.service"

   if [ "$system_run" = "true" ]; then
      systemctl --system daemon-reload
      systemctl enable "anon-ws-disable-stacked-tor_autogen_${file_name}.socket"

      ## 'restart' rather than 'start' required to support running this script
      ## during runtime due to the following.
      ##
      ## Jun 06 05:38:49 host systemd[1]: anon-ws-disable-stacked-tor_autogen__var_run_tor_socks.socket: Socket unit configuration has changed while unit has been running, no open socket file descriptor left. The socket unit is not functional until restarted.
      systemctl restart "anon-ws-disable-stacked-tor_autogen_${file_name}.socket"
   fi

   ## Append lintian override for each auto generated systemd unit file.
   echo "\
anon-ws-disable-stacked-tor: systemd-service-file-missing-install-key lib/systemd/system/anon-ws-disable-stacked-tor_autogen_${file_name}.service" >> ./usr/share/lintian/overrides/anon-ws-disable-stacked-tor

done
