-
Bob Mottram authored
Sending the log entries is overkill
Bob Mottram authoredSending the log entries is overkill
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
freedombone-utils-onion 18.73 KiB
#!/bin/bash
# _____ _ _
# | __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
# | __| _| -_| -_| . | . | | . | . | | -_|
# |__| |_| |___|___|___|___|_|_|_|___|___|_|_|___|
#
# Freedom in the Cloud
#
# Onion functions
#
# License
# =======
#
# Copyright (C) 2014-2018 Bob Mottram <bob@freedombone.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# The maximum amount of traffic per day in gigabytes
TOR_MAX_TRAFFIC_PER_MONTH_GB=10
USE_V2_ONION_ADDRESS=
HIDDEN_SERVICE_PATH='/var/lib/tor/hidden_service_'
ONION_SERVICES_FILE=/etc/torrc.d/${PROJECT_NAME}
function torrc_migrate {
if [ -f "$ONION_SERVICES_FILE" ]; then
if grep -q "#%include /etc/torrc.d" /etc/tor/torrc; then
sed -i 's|#%include /etc/torrc.d|%include /etc/torrc.d|g' /etc/tor/torrc
systemctl restart tor
fi
return
fi
systemctl stop tor
mkdir /etc/torrc.d
grep "HiddenServiceDir\\|HiddenServiceVersion\\|HiddenServicePort" /etc/tor/torrc | grep -v "#HiddenServiceDir" >> "$ONION_SERVICES_FILE"
if ! grep "HiddenServiceVersion" "$ONION_SERVICES_FILE"; then
systemctl restart tor
return
fi
if grep -q "#%include /etc/torrc.d" /etc/tor/torrc; then
sed -i 's|#%include /etc/torrc.d|%include /etc/torrc.d|g' /etc/tor/torrc
else
echo "%include /etc/torrc.d" >> /etc/tor/torrc
fi
{ echo 'DNSPort 5300';
echo 'DNSListenAddress 127.0.0.1';
echo 'AutomapHostsOnResolve 1'; } > /etc/torrc.d/dns
sed -i '/DNSPort 5300/d' /etc/tor/torrc
sed -i '/DNSListenAddress 127.0.0./d' /etc/tor/torrc
sed -i '/AutomapHostsOnResolve 1/d' /etc/tor/torrc
sed -i '/HiddenServiceDir/d' /etc/tor/torrc
sed -i '/HiddenServiceVersion/d' /etc/tor/torrc
sed -i '/HiddenServicePort/d' /etc/tor/torrc
systemctl restart tor
}
function add_email_hostname {
extra_email_hostname="$1"
email_hostnames=$(grep "dc_other_hostnames" /etc/exim4/update-exim4.conf.conf | awk -F "'" '{print $2}')
if [[ "$email_hostnames" != *"$extra_email_hostname"* ]]; then
sed -i "s|dc_other_hostnames=.*|dc_other_hostnames='$email_hostnames;$extra_email_hostname'|g" /etc/exim4/update-exim4.conf.conf
update-exim4.conf
dpkg-reconfigure --frontend noninteractive exim4-config
systemctl restart saslauthd
fi
}
function onion_update {
# update so that new onion services appear
systemctl restart tor
}
function wait_for_onion_service_base {
onion_service_name="$1"
sleep_ctr=0
while [ ! -f "${HIDDEN_SERVICE_PATH}${onion_service_name}/hostname" ]; do
sleep 1
sleep_ctr=$((sleep_ctr + 1))
if [ $sleep_ctr -gt 10 ]; then
break
fi
done
}
function wait_for_onion_service {
onion_service_name="$1"
wait_for_onion_service_base "${onion_service_name}"
if [ ! -f "${HIDDEN_SERVICE_PATH}${onion_service_name}/hostname" ]; then
# try a second time
onion_update
wait_for_onion_service_base "${onion_service_name}"
fi
sync
}
function remove_onion_service {
onion_service_name="$1"
onion_service_port_to=$2
nick="$3"
if [ ${#nick} -gt 0 ]; then
sed -i "/stealth ${nick}/d" "$ONION_SERVICES_FILE"
fi
sed -i "/hidden_service_${onion_service_name}/,+1 d" "$ONION_SERVICES_FILE"
sed -i "/hidden_service_${onion_service_name}_mobile/,+1 d" "$ONION_SERVICES_FILE"
sed -i "/127.0.0.1:${onion_service_port_to}/d" "$ONION_SERVICES_FILE"
if [ "$3" ]; then
sed -i "/127.0.0.1:${3}/d" "$ONION_SERVICES_FILE"
if [ "$4" ]; then
sed -i "/127.0.0.1:${4}/d" "$ONION_SERVICES_FILE"
if [ "$5" ]; then
sed -i "/127.0.0.1:${5}/d" "$ONION_SERVICES_FILE"
fi
fi
fi
if [ -d "${HIDDEN_SERVICE_PATH}${onion_service_name}" ]; then
rm -rf "${HIDDEN_SERVICE_PATH}${onion_service_name}"
fi
if [ -d "${HIDDEN_SERVICE_PATH}${onion_service_name}_mobile" ]; then
rm -rf "${HIDDEN_SERVICE_PATH}${onion_service_name}_mobile"
fi
remove_completion_param "${onion_service_name} onion domain"
onion_update
}
function add_onion_service {
onion_service_name="$1"
onion_service_port_from=$2
onion_service_port_to=$3
onion_stealth_name="$4"
if [ -f "${HIDDEN_SERVICE_PATH}${onion_service_name}/hostname" ]; then
cat "${HIDDEN_SERVICE_PATH}${onion_service_name}/hostname"
USE_V2_ONION_ADDRESS=
return
fi
if [ ! -d /var/lib/tor ]; then
echo $"No Tor installation found. ${onion_service_name} onion site cannot be configured."
USE_V2_ONION_ADDRESS=
exit 877367
fi
if ! grep -q "hidden_service_${onion_service_name}" "$ONION_SERVICES_FILE"; then
echo "HiddenServiceDir ${HIDDEN_SERVICE_PATH}${onion_service_name}/" >> "$ONION_SERVICES_FILE"
if [ ! $USE_V2_ONION_ADDRESS ]; then
echo 'HiddenServiceVersion 3' >> "$ONION_SERVICES_FILE"
else
echo 'HiddenServiceVersion 2' >> "$ONION_SERVICES_FILE"
fi
echo "HiddenServicePort ${onion_service_port_from} 127.0.0.1:${onion_service_port_to}" >> "$ONION_SERVICES_FILE"
if [ ${#onion_stealth_name} -gt 0 ]; then
echo "HiddenServiceAuthorizeClient stealth ${onion_stealth_name}" >> "$ONION_SERVICES_FILE"
fi
fi
USE_V2_ONION_ADDRESS=
onion_update
function_check wait_for_onion_service
wait_for_onion_service "${onion_service_name}"
if [ ! -f "${HIDDEN_SERVICE_PATH}${onion_service_name}/hostname" ]; then
ls -lh "${HIDDEN_SERVICE_PATH}${onion_service_name}/hostname"
echo $"${onion_service_name} onion site hostname not found"
exit 763624
fi
onion_address=$(cat "${HIDDEN_SERVICE_PATH}${onion_service_name}/hostname")
# Record the domain in the completion file
set_completion_param "${onion_service_name} onion domain" "${onion_address}"
echo "$onion_address"
}
function set_default_onion_domains {
# If sites are only visible via Tor then for installation
# purposes assign them some default domain names
if [[ $ONION_ONLY == "no" ]]; then
return
fi
POSTACTIV_DOMAIN_NAME='postactiv.local'
GNUSOCIAL_DOMAIN_NAME='gnusocial.local'
HTMLY_DOMAIN_NAME='htmly.local'
BLUDIT_DOMAIN_NAME='bludit.local'
DOKUWIKI_DOMAIN_NAME='dokuwiki.local'
DEFAULT_DOMAIN_NAME="${LOCAL_NAME}.local"
GOGS_DOMAIN_NAME='gogs.local'
}
function create_avahi_onion_domains {
if [[ $SYSTEM_TYPE == "mesh"* ]]; then
return
fi
if [ ! -d /etc/avahi/services ]; then
return
fi
if [ $GNUSOCIAL_DOMAIN_NAME ]; then
function_check create_avahi_service
create_avahi_service gnusocial http tcp "$GNUSOCIAL_ONION_PORT"
fi
if [ $HTMLY_DOMAIN_NAME ]; then
function_check create_avahi_service
create_avahi_service blog http tcp "$HTMLY_ONION_PORT"
fi
if [ $GOGS_DOMAIN_NAME ]; then
function_check create_avahi_service
create_avahi_service git http tcp "$GIT_ONION_PORT"
fi
if [ $DOKUWIKI_DOMAIN_NAME ]; then
function_check create_avahi_service
create_avahi_service dokuwiki http tcp "$DOKUWIKI_ONION_PORT"
fi
}
function allow_ssh_to_onion_address {
if [[ $SYSTEM_TYPE == "mesh"* ]]; then
return
fi
if [ ! -d "/home/$MY_USERNAME/.ssh" ]; then
mkdir "/home/$MY_USERNAME/.ssh"
fi
if [ ! -d /etc/tor ]; then
echo $'Tor not found when updating ssh'
exit 528257
fi
if ! grep -q "onion" "/home/$MY_USERNAME/.ssh/config"; then
echo 'Host *.onion' >> "/home/$MY_USERNAME/.ssh/config"
echo 'ProxyCommand connect -R remote -5 -S 127.0.0.1:9050 %h %p' >> "/home/$MY_USERNAME/.ssh/config"
fi
}
function enable_ssh_via_onion {
if [[ $SYSTEM_TYPE == "mesh"* ]]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
echo 'N' | $INSTALL_PACKAGES_BACKPORTS tor
$INSTALL_PACKAGES connect-proxy
if ! grep -q 'Host *.onion' "/home/$MY_USERNAME/.ssh/config"; then
if [ ! -d "/home/$MY_USERNAME/.ssh" ]; then
mkdir "/home/$MY_USERNAME/.ssh"
fi
echo 'Host *.onion' >> "/home/$MY_USERNAME/.ssh/config"
echo 'ProxyCommand connect -R remote -5 -S 127.0.0.1:9050 %h %p' >> "/home/$MY_USERNAME/.ssh/config"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.ssh"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.ssh/config"
fi
if ! grep -q 'Host *.onion' /root/.ssh/config; then
if [ ! -d /root/.ssh ]; then
mkdir /root/.ssh
fi
echo 'Host *.onion' >> /root/.ssh/config
echo 'ProxyCommand connect -R remote -5 -S 127.0.0.1:9050 %h %p' >> /root/.ssh/config
fi
if ! grep -q 'Host *.onion' /etc/skel/.ssh/config; then
if [ ! -d /etc/skel/.ssh ]; then
mkdir /etc/skel/.ssh
fi
echo 'Host *.onion' >> /etc/skel/.ssh/config
echo 'ProxyCommand connect -R remote -5 -S 127.0.0.1:9050 %h %p' >> /etc/skel/.ssh/config
fi
mark_completed "${FUNCNAME[0]}"
}
function configure_ssh_onion {
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [[ $SYSTEM_TYPE == "mesh"* ]]; then
return
fi
SSH_ONION_HOSTNAME=$(add_onion_service ssh "${SSH_PORT}" "${SSH_PORT}")
if [[ "$SSH_ONION_HOSTNAME" != *'.onion' ]]; then
echo $'ssh onion site not generated'
exit 624128
fi
set_completion_param "ssh onion domain" "${SSH_ONION_HOSTNAME}"
add_email_hostname "${SSH_ONION_HOSTNAME}"
mark_completed "${FUNCNAME[0]}"
}
function check_tor_health {
{ echo '#!/bin/bash';
echo "status=\$(${PROJECT_NAME}-tor-health)";
echo "ADMIN_USER=\$(grep \"MY_USERNAME=\" ~/${PROJECT_NAME}.cfg | awk -F '=' '{print \$2}')";
echo 'FAILS_FILE=/var/log/tor/fails';
echo "if [[ \"\$status\" == 'G'* ]]; then";
echo " if [ -f \$FAILS_FILE ]; then";
echo " rm \$FAILS_FILE";
echo " /bin/bash /usr/local/bin/${PROJECT_NAME}-notification -m \"[${PROJECT_NAME}] Tor status is \$status\" -s \"[${PROJECT_NAME}] Tor status is now \$status\"";
echo ' fi';
echo ' exit 0';
echo 'fi';
echo "if [ ! -f \$FAILS_FILE ]; then";
echo " /bin/bash /usr/local/bin/${PROJECT_NAME}-notification -m \"[${PROJECT_NAME}] Tor status is \$status\" -s \"[${PROJECT_NAME}] Tor status is \$status\"";
echo " echo \"\$status\" > \$FAILS_FILE";
echo 'else';
echo " prev_status=\$(cat \$FAILS_FILE)";
echo " if [[ \"\$prev_status\" != \"\$status\" ]]; then";
echo " /bin/bash /usr/local/bin/${PROJECT_NAME}-notification -m \"[${PROJECT_NAME}] Tor status is \$status\" -s \"[${PROJECT_NAME}] Tor status is \$status\"";
echo " echo \"\$status\" > \$FAILS_FILE";
echo ' fi';
echo 'fi'; } > /usr/bin/check_tor_health
chmod +x /usr/bin/check_tor_health
if ! grep -q 'check_tor_health' /etc/crontab; then
cron_add_mins 10 "/usr/bin/check_tor_health"
fi
}
function install_tor {
if [[ $SYSTEM_TYPE == "mesh*" ]]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
$INSTALL_PACKAGES_BACKPORTS tor
if [ ! -f /etc/tor/torrc ]; then
echo 'Tor failed to install'
exit 38259
fi
# For torify
$INSTALL_PACKAGES torsocks
if [ ! -d /etc/torrc.d ]; then
mkdir /etc/torrc.d
fi
sed -i 's|#%include /etc/torrc.d|%include /etc/torrc.d|g' /etc/tor/torrc
if ! grep -q '%include /etc/torrc.d' /etc/tor/torrc; then
echo '%include /etc/torrc.d' >> /etc/tor/torrc
fi
echo 'Log notice file /var/log/tor/notices.log' > /etc/torrc.d/logging
echo "AccountingMax $TOR_MAX_TRAFFIC_PER_MONTH_GB GBytes" > /etc/torrc.d/maxtraffic
mark_completed "${FUNCNAME[0]}"
}
# see https://trac.torproject.org/projects/tor/wiki/doc/TransparentProxy
# Local Redirection and Anonymizing Middlebox
function route_outgoing_traffic_through_tor {
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [[ $ROUTE_THROUGH_TOR != "yes" ]]; then
return
fi
echo 'N' | $INSTALL_PACKAGES_BACKPORTS tor
echo 'N' | $INSTALL_PACKAGES_BACKPORTS tor-arm
### set variables
# Destinations you don't want routed through Tor
_non_tor="192.168.1.0/24 192.168.0.0/24"
# The user that Tor runs as
_tor_uid="debian-tor"
# Tor's TransPort
_trans_port="9040"
# Your internal interface
_int_if="eth0"
### Set iptables *nat
iptables -t nat -A OUTPUT -o lo -j RETURN
iptables -t nat -A OUTPUT -m owner --uid-owner $_tor_uid -j RETURN
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 53
# Allow clearnet access for hosts in $_non_tor
for _clearnet in $_non_tor; do
iptables -t nat -A OUTPUT -d "$_clearnet" -j RETURN
iptables -t nat -A PREROUTING -i $_int_if -d "$_clearnet" -j RETURN
done
# Redirect all other pre-routing and output to Tor
iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports $_trans_port
iptables -t nat -A PREROUTING -i $_int_if -p udp --dport 53 -j REDIRECT --to-ports 53
iptables -t nat -A PREROUTING -i $_int_if -p tcp --syn -j REDIRECT --to-ports $_trans_port
### set iptables *filter
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow clearnet access for hosts in $_non_tor
for _clearnet in $_non_tor 127.0.0.0/8; do
iptables -A OUTPUT -d "$_clearnet" -j ACCEPT
done
# Allow only Tor output
iptables -A OUTPUT -m owner --uid-owner $_tor_uid -j ACCEPT
iptables -A OUTPUT -j REJECT
function_check save_firewall_settings
save_firewall_settings
if ! grep -q "fs.file-max" /etc/sysctl.conf; then
echo "fs.file-max=100000" >> /etc/sysctl.conf
/sbin/sysctl -p -q
fi
resolvconf=/etc/resolvconf/resolv.conf.d/head
echo 'domain localdomain' > $resolvconf
echo 'search localdomain' >> $resolvconf
echo 'nameserver 127.0.0.1' >> $resolvconf
resolvconf -u
if ! grep -q "VirtualAddrNetworkIPv4" /etc/tor/torrc; then
echo 'VirtualAddrNetworkIPv4 10.192.0.0/10' >> /etc/tor/torrc
fi
if ! grep -q "AutomapHostsOnResolve" /etc/tor/torrc; then
echo 'AutomapHostsOnResolve 1' >> /etc/tor/torrc
fi
if ! grep -q "TransPort" /etc/tor/torrc; then
echo 'TransPort 9040' >> /etc/tor/torrc
fi
if ! grep -q "TransListenAddress 127.0.0.1" /etc/tor/torrc; then
echo 'TransListenAddress 127.0.0.1' >> /etc/tor/torrc
fi
if ! grep -q "TransListenAddress $LOCAL_NETWORK_STATIC_IP_ADDRESS" /etc/tor/torrc; then
echo "TransListenAddress $LOCAL_NETWORK_STATIC_IP_ADDRESS" >> /etc/tor/torrc
fi
if ! grep -q "DNSPort" /etc/tor/torrc; then
echo 'DNSPort 53' >> /etc/tor/torrc
fi
if ! grep -q "DNSListenAddress 127.0.0.1" /etc/tor/torrc; then
echo 'DNSListenAddress 127.0.0.1' >> /etc/tor/torrc
fi
if ! grep -q "DNSListenAddress $LOCAL_NETWORK_STATIC_IP_ADDRESS" /etc/tor/torrc; then
echo "DNSListenAddress $LOCAL_NETWORK_STATIC_IP_ADDRESS" >> /etc/tor/torrc
fi
mark_completed "${FUNCNAME[0]}"
}
function get_app_onion_address {
app_name="$1"
mobilestr="$2"
if [ ${#mobilestr} -gt 0 ]; then
app_name="mobile${app_name}"
fi
if grep -q "${app_name} onion domain" "$COMPLETION_FILE"; then
if grep -q "${app_name} onion domain" "$COMPLETION_FILE"; then
grep "${app_name} onion domain" "${COMPLETION_FILE}" | head -n 1 | awk -F ':' '{print $2}'
return
fi
fi
echo ""
}
function tor_add_bridge {
bridge_ip_address="$1"
bridge_port="$2"
bridge_key="$3"
bridge_type='obfs4'
if [[ "$bridge_ip_address" != *"."* ]]; then
return
fi
if [ ${#bridge_port} -eq 0 ]; then
return
fi
if [ ${#bridge_key} -eq 0 ]; then
return
fi
$INSTALL_PACKAGES obfs4proxy
if [ ! -f /etc/torrc.d/bridges ]; then
{ echo 'ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy managed';
echo 'UseBridges 1';
echo "Bridge $bridge_type ${bridge_ip_address}:${bridge_port} ${bridge_key}"; } > /etc/torrc.d/bridges
else
if ! grep -q "Bridge $bridge_type ${bridge_ip_address}:${bridge_port} ${bridge_key}" /etc/torrc.d/bridges; then
echo "Bridge $bridge_type ${bridge_ip_address}:${bridge_port} ${bridge_key}" >> /etc/torrc.d/bridges
fi
fi
systemctl restart tor
}
function tor_remove_bridge {
bridge_ip_address="$1"
bridge_type='obfs4'
if [[ "$bridge_ip_address" == *"."* ]]; then
bridge_str="Bridge $bridge_type ${bridge_ip_address}"
else
if grep -q " ${bridge_ip_address}" /etc/torrc.d/bridges; then
bridge_str=" ${bridge_ip_address}"
else
return
fi
fi
if grep -q "${bridge_str}" /etc/torrc.d/bridges; then
sed -i "/${bridge_str}/d" /etc/torrc.d/bridges
fi
# If there are no bridges remaining then remove the file
if ! grep -q "Bridge " /etc/torrc.d/bridges; then
rm /etc/torrc.d/bridges
fi
systemctl restart tor
}
function tor_create_bridge_relay {
read_config_param 'TOR_BRIDGE_PORT'
read_config_param 'TOR_BRIDGE_NICKNAME'
read_config_param 'MY_EMAIL_ADDRESS'
if [ ! "$TOR_BRIDGE_PORT" ]; then
return
fi
if [ ${#TOR_BRIDGE_PORT} -eq 0 ]; then
return
fi
if [ ${#TOR_BRIDGE_NICKNAME} -eq 0 ]; then
return
fi
$INSTALL_PACKAGES obfs4proxy
{ echo 'BridgeRelay 1';
echo 'ServerTransportPlugin obfs4 exec /usr/bin/obfs4proxy';
echo "ExtORPort $TOR_BRIDGE_PORT";
echo "ContactInfo $MY_EMAIL_ADDRESS";
echo "Nickname $TOR_BRIDGE_NICKNAME"; } > /etc/torrc.d/bridgerelay
firewall_add tor_bridge "$TOR_BRIDGE_PORT" tcp
systemctl restart tor
}
function tor_remove_bridge_relay {
if [ -f /etc/torrc.d/bridgerelay ]; then
rm /etc/torrc.d/bridgerelay
fi
read_config_param 'TOR_BRIDGE_PORT'
firewall_remove "$TOR_BRIDGE_PORT" tcp
systemctl restart tor
}
# NOTE: deliberately no exit 0