#!/bin/bash
# -*-mode: sh; tab-width: 8; coding: utf-8-unix -*-
# was /usr/local/bin/proxy_whonix_tor_start.bash

ROLE=proxy
USAGE="config|start|stop|status|restart|verify|test"

[ $( id -u ) -eq 0 ] || { ERROR $prog you must be root ; exit 1 ; }
prog=$( basename $0 .bash )
. /usr/local/bin/usr_local_tput.bash || exit 3

. /usr/local/sbin/proxy_whonix_lib.bash || exit 1
. /usr/local/sbin/proxy_tor_lib.bash || exit 2
rm -f /etc/torrc.d/*~

[ -f /usr/local/etc/testforge/testforge.bash ] && . /usr/local/etc/testforge/testforge.bash
[ -z "$PRIV_TOR_OWNER" ] && grep -q ^debian-tor /etc/passwd && PRIV_TOR_OWNER=debian-tor
[ -z "$PRIV_TOR_OWNER" ] && grep -q ^tor /etc/passwd && PRIV_TOR_OWNER=tor

NEEDED_SCRIPTS="
/usr/local/sbin/proxy_tor_lib.bash
/usr/local/bin/proxy_ping_test.bash
"

# to stop
# 4269 ttyS0    S      0:00 su -c tor -s /bin/sh debian-tor
# 4272 ?        Ss     0:00 sh -c tor
# 4273 ?        S      0:02 tor
# 4355 ?        S      0:00 timeout --kill-after=5s 10s /usr/lib/helper-scripts/tor_circuit_established_check.py
# 4356 ?        R      0:00 /usr/bin/python3 -u /usr/lib/helper-scripts/tor_circuit_established_check.py
## gateway_tor_stop
gateway_tor_stop () {
    local debian

    [ -s /tmp/tor.pid ] && \
	DBUG $prog kill $( cat /tmp/tor.pid ) && \
	kill $( cat /tmp/tor.pid ) 2>/dev/null && \
	rm /tmp/tor.pid
    rm -f /tmp/tor.log /tmp/tor.err
    debian=$PRIV_TOR_OWNER
    pkill -u $debian
    [ -s /tmp/tog.pid ] && \
	kill $( cat /tmp/tog.pid ) 2>/dev/null \
	&& rm /tmp/tog.pid
    systemctl stop vanguards
    # systemctl start onion-grater >/dev/null && systemctl stop onion-grater
    # echo 1|sudo dd of=/proc/sys/net/ipv4/tcp_tw_reuse
    netstat -npet4

    return 0
}

## gateway_tor_torrc
gateway_tor_torrc () {
    local file IP
    # file=/etc/torrc.d/50_user.conf
    file=/usr/local/etc/torrc.d/50_user.conf
    if [ ! -f $file ] ; then
	cat > $file <<EOF
# Tor user specific configuration file
#
# Add user modifications below this line:
############################################
Socks5ProxyUsername foo
Socks5ProxyPassword bar
SafeLogging 0
SocksPort 10.0.2.15:9050
DNSPort 10.0.2.15:9053
HTTPTunnelPort 10.0.2.15:9128 IsolateDestAddr
TransPort 10.0.2.15:9040 IsolateClientAddr IsolateClientProtocol IsolateDestAddr IsolateDestPort
DisableNetwork 0
ControlSocket /run/tor/control
EOF
    else
	IP=10.0.2.15
	proxy_tor_torrc_update $file $IP
    fi
    proxy_tor_torrc_exclude $file
    return 0
}

## gateway_tor_init_config_gateway_conf
gateway_tor_init_config_gateway_conf () {
    local elt file
    file=/etc/whonix_firewall.d/30_whonix_gateway_default.conf
    for elt in GATEWAY_ALLOW_INCOMING_ICMP GATEWAY_ALLOW_INCOMING_SSH ; do
	grep -q $elt=1 $file || \
	    sed -e "s/$elt=.*/$elt=1/"  -i $file
      done
    for elt in 22 9050 9053 9040 9128 ; do
	grep -q '^EXTERNAL_OPEN_PORTS.=" '$elt' "' \
	     /etc/whonix_firewall.d/30_whonix_gateway_default.conf && continue
	echo 'EXTERNAL_OPEN_PORTS+=" '$elt' "' >> $file
    done
    return 0
}

## gateway_tor_init_check_iptables
gateway_tor_init_check_iptables () {
    local rule changed
    changed=0
    rule='-A INPUT -i eth0 -p udp -m udp --dport 9053 -j ACCEPT'
    if ! proxy_iptables_save | grep -q -e "$rule" ; then
        [ $changed -eq 0 ] && proxy_iptables -D INPUT -j DROP
	proxy_iptables $rule
	changed=1
    fi
    rule='-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT'
    if ! proxy_iptables_save | grep -q -e "$rule" ; then
	[ $changed -eq 0 ] && proxy_iptables -D INPUT -j DROP
	proxy_iptables $rule
	changed=1
    fi
    rule='-A INPUT -i eth0 -p tcp -m tcp --dport 9128 -j ACCEPT'
    if ! proxy_iptables_save | grep -q -e "$rule" ; then
	[ $changed -eq 0 ] && proxy_iptables -D INPUT -j DROP
	proxy_iptables $rule
	changed=1
    fi
    [ $changed -gt 0 ] && proxy_iptables -A INPUT -j DROP
    return 0
}
# systemctl --no-pager status tor@default

## tor_start_not_running
tor_start_not_running () {
    local retval

    retval=0
    if netstat -nlp4 2>&1| grep '15:90.*/tor' ; then
	DBUG $prog tor is already running
	retval=2
    elif ps ax | grep -v grep | grep "su -c tor -s /bin/sh $PRIV_TOR_OWNER" ; then
	DBUG $prog tor is already running
	retval=3
    elif ls -l /run/tor/socket 2>/dev/null ; then
	DBUG $prog tor is already running
	retval=4
    fi
    tor_grep_log
    return $retval
}

## gateway_tor_config_tor
gateway_tor_config_tor () {

    gateway_tor_init_check_iptables || exit 2$?
    gateway_tor_torrc
    gateway_tor_init_config_gateway_conf
    rm -f /usr/local/etc/torrc.d/*~
    return $?
}

## tor_start_verify_config
tor_start_verify_config () {
    # tor --verify-config # || exit 2$?
    su -c 'tor --verify-config' -s /bin/sh $PRIV_TOR_OWNER \
	| grep -v 'notice\|DisableNetwork'
    # || exit 2
    return 0
}

## tor_prepare_to_start
tor_prepare_to_start () {
    #su -c '/etc/init.d/tor stop' -s /bin/sh $PRIV_TOR_OWNER
    #sleep 5

    [ -d /run/tor/  ] && rm -f /run/tor/* || mkdir /run/tor
    # systemd overrides these
    chown $PRIV_TOR_OWNER.$PRIV_TOR_OWNER /run/tor
    chmod 0700  /run/tor/

    gateway_tor_stop
    # systemctl daemon-reload
    rm -f /run/tor/log.err /tmp/log.err
    rm -f /run/tor/log /tmp/log.log
    rm -f /run/tor/tor.pid /tmp/log.pid

    sed '/DisableNetwork/d'  -i /usr/local/etc/torrc.d/50_user.conf

    return 0
}

## tor_after_start
tor_after_start () {

    [ -s /tmp/tor.err ] && ERROR $prog /tmp/tor.err  && cat /tmp/tor.err && return 6
    grep '\[warn\]' /tmp/tor.log
    grep '\[err\]' /tmp/tor.log && ERROR $prog /tmp/tor.log && return 7

    ls  /run/tor/log* >/dev/null && \
	sed -e '/configured a non-loopback address/d' -i /run/tor/log*
    chmod 750 /run/tor/
    chmod 640 /run/tor/log
    INFO checked /tmp/tor.log /tmp/tor.err

    INFO starting onion-grater
    # systemctl start onion-grater
    pidof /usr/lib/onion-grater || return 0
    /usr/lib/onion-grater --listen-interface eth1 &
    echo -n $! >/tmp/tog.pid
    return 0
}

tor_grep_log () {
    local log

    [ -f /run/tor/log ] && log=/run/tor/log || log=/tmp/tor.log
    [ -f $log ] || { WARN $prog $log not found ; return 1 ; }

    INFO grep % $log
    grep % $log | grep -v 5%

    return 0
}

tor_test () {
    tor_grep_log
    tor_qemu_status || return 1$?
    return 0
}

tor_qemu_status () {
    local pid

    pid=$( pidof /usr/sbin/qemu-ga )
    [ $? -eq 0 -a -n "$pid" ] || \
        { WARN $prog qemu-qa not running; return 1 ; }
    lsof -p $pid | grep -q /dev/v || \
	{ WARN /usr/sbin/qemu-ga not bound to /dev ; return 1 ; }

    return 0
}

tor_status () {
    [ -f /tmp/tor.pid ] && \
	[ $( wc -c /tmp/tor.pid|sed -e 's/ .*//' ) -le 1 ] && \
	rm /tmp/tor.pid

    if [ -f /tmp/tor.pid ]; then
	ps -p "$( cat /tmp/tor.pid )"
      elif [ -f /run/tor/tor.pid ] ; then
	ps -p "$( cat /run/tor/tor.pid )"
      else
	WARN $prog no /tmp/tor.pid or /run/tor/tor.pid
      fi

    [ ! -f /usr/local/src/helper-scripts/tor_bootstrap_check.py ] || \
      python3 /usr/local/src/helper-scripts/tor_bootstrap_check.py \
	|| return 1

    debian=$( grep -q ^$PRIV_TOR_OWNER /etc/passwd && echo $PRIV_TOR_OWNER || echo tor )
    INFO $prog $debian processes:
    ps -g $debian

    tor_qemu_status || return 1$?
    tor_start_not_running && return 2$?

 #  /usr/lib/helper-scripts/tor_circuit_established_check.py

    return 0
}

gateway_tor_verify () {
    tor_start_verify_config || return 1

    return 0
}

gateway_tor_start () {
    local debian
    # Nov 09 21:00:27 host vanguards[715]: WARNING[Mon Nov 09 21:00:27 2020]: Tor daemon connection failed: [Errno 24] Too many open files. Trying again...

    # debian-tor	soft	nofile		100000
    # /etc/security/limits.conf

    gateway_tor_config_tor || return 2$?
    tor_start_not_running || return 3$?

    gateway_tor_verify || return 4$?
    tor_prepare_to_start

    INFO startiing tor - see /tmp/tor.err /tmp/tor.log
    #su -c '/etc/init.d/tor start' -s /bin/sh $PRIV_TOR_OWNER
    #netstat -nlp -t inet | grep "$IP:9128" || systemctl --no-pager restart tor@default || return 4$?
    su -c 'tor' -s /bin/sh $PRIV_TOR_OWNER 2>/tmp/tor.err >/tmp/tor.log &
    echo -n $! >/tmp/tor.pid

    sleep 15

    tor_after_start
    tor_status
    return 0
}

if [ "$#" -eq 0 ] ; then
    echo USAGE: $prog "$USAGE"

elif [ "$d1#" = '--help' ] ; then
    echo USAGE: $prog "$USAGE" or:
    grep '^## ' $0 | sed -e 's/^## //'

  ## config
  elif [ $1 = config ] ; then
    INFO $prog $1
    gateway_tor_config_tor  || exit 1$?

  ## stop -
  elif [ $1 = stop ] ; then
    INFO $prog $1
    gateway_tor_stop
    exit $?

  ## status
  elif [ $1 = status ] ; then
    INFO $prog tor_status
    tor_status || exit $?
    exit 0

  ## start
  elif [ "$1" = gateway -o "$1" = start ] ; then
    INFO $prog tor_start
    gateway_tor_start
    exit $?

  ## restart
  elif [ "$1" = restart ] ; then
    INFO $prog tor_restart
    gateway_tor_stop || exit 1$?
    sleep 2
    gateway_tor_start
    exit $?

  ## verify
  elif [ "$1" = verify ] ; then
    tor_start_verify_config

  elif [ "$1" = test ] ; then
    tor_test

  elif [ "$1" = '--help' -o "$1" = '-h' ] ; then
    echo USAGE: $prog  "$USAGE or:"
    grep '^## ' $0 | sed -e 's/## //'

  else
    eval "$@" || exit $?
fi

exit 0
