#!/bin/bash # # .---. . . # | | | # |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-. # | | (.-' (.-' ( | ( )| | | | )( )| | (.-' # ' ' --' --' -' - -' ' ' -' -' -' ' - --' # # Freedom in the Cloud # # Onion functions # # License # ======= # # Copyright (C) 2014-2018 Bob Mottram # # 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 . # 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_' function add_email_hostname { extra_email_hostname="$1" email_hostnames=$(cat /etc/exim4/update-exim4.conf.conf | grep "dc_other_hostnames" | awk -F "'" '{print $2}') if [[ "$email_hostnames" != *"$extra_email_hostname"* ]]; then sed -i "s|dc_other_hostnames=.*|dc_other_hostnames='$emailhostnames;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" /etc/tor/torrc fi sed -i "/hidden_service_${onion_service_name}/,+1 d" /etc/tor/torrc sed -i "/hidden_service_${onion_service_name}_mobile/,+1 d" /etc/tor/torrc sed -i "/127.0.0.1:${onion_service_port_to}/d" /etc/tor/torrc if [ $3 ]; then sed -i "/127.0.0.1:${3}/d" /etc/tor/torrc if [ $4 ]; then sed -i "/127.0.0.1:${4}/d" /etc/tor/torrc if [ $5 ]; then sed -i "/127.0.0.1:${5}/d" /etc/tor/torrc fi fi fi if [ -d ${HIDDEN_SERVICE_PATH}${onion_service_name} ]; then shred -zu ${HIDDEN_SERVICE_PATH}${onion_service_name}/* rm -rf ${HIDDEN_SERVICE_PATH}${onion_service_name} fi if [ -d ${HIDDEN_SERVICE_PATH}${onion_service_name}_mobile ]; then shred -zu ${HIDDEN_SERVICE_PATH}${onion_service_name}_mobile/* 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 echo $(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}" /etc/tor/torrc; then echo "HiddenServiceDir ${HIDDEN_SERVICE_PATH}${onion_service_name}/" >> /etc/tor/torrc if [ ! $USE_V2_ONION_ADDRESS ]; then echo 'HiddenServiceVersion 3' >> /etc/tor/torrc else echo 'HiddenServiceVersion 2' >> /etc/tor/torrc fi echo "HiddenServicePort ${onion_service_port_from} 127.0.0.1:${onion_service_port_to}" >> /etc/tor/torrc if [ ${#onion_stealth_name} -gt 0 ]; then echo "HiddenServiceAuthorizeClient stealth ${onion_stealth_name}" >> /etc/tor/torrc 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' GHOST_DOMAIN_NAME='ghost.local' DOKUWIKI_DOMAIN_NAME='dokuwiki.local' DEFAULT_DOMAIN_NAME="${LOCAL_NAME}.local" GIT_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 [ $GIT_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 apt-get -yq install tor 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 install_tor { if [[ $SYSTEM_TYPE == "mesh*" ]]; then return fi if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then return fi apt-get -yq -t stretch-backports install tor if [ ! -f /etc/tor/torrc ]; then echo 'Tor failed to install' exit 38259 fi # For torify apt-get -yq install torsocks # turn off logging sed -i 's|#Log notice file.*|Log notice file /dev/null|g' /etc/tor/torrc sed -i 's|Log notice file.*|Log notice file /dev/null|g' /etc/tor/torrc # Restrict traffic sed -i "s|#AccountingMax.*|AccountingMax $TOR_MAX_TRAFFIC_PER_MONTH_GB GBytes|g" /etc/tor/torrc sed -i "s|AccountingMax.*|AccountingMax $TOR_MAX_TRAFFIC_PER_MONTH_GB GBytes|g" /etc/tor/torrc mark_completed "${FUNCNAME[0]}" } function resolve_dns_via_tor { if [[ $SYSTEM_TYPE == "mesh"* ]]; then return fi if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then return fi if [ ! -f /etc/tor/torrc ]; then echo $'tor was not installed' exit 52952 fi # resolve DNS via tor if ! grep -q 'DNSPort 53' /etc/tor/torrc; then echo 'DNSPort 53' >> /etc/tor/torrc echo 'AutomapHostsOnResolve 1' >> /etc/tor/torrc echo 'AutomapHostsSuffixes .exit,.onion' >> /etc/tor/torrc onion_update fi # don't change resolv.conf sed -i 's|, domain-name-servers||g' /etc/dhcp/dhclient.conf # point resolv.conf to tor resolvconf=/etc/resolvconf/resolv.conf.d/head echo 'nameserver 127.0.0.1:53' > $resolvconf resolvconf -u 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 apt-get -yq install tor 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 echo $(cat ${COMPLETION_FILE} | grep "${app_name} onion domain" | 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 apt-get -yq install obfs4proxy if grep -q "ClientTransportPlugin" /etc/tor/torrc; then sed -i 's|#ClientTransportPlugin|ClientTransportPlugin|g' /etc/tor/torrc sed -i 's|# ClientTransportPlugin|ClientTransportPlugin|g' /etc/tor/torrc sed -i 's|ClientTransportPlugin.*|ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy managed|g' /etc/tor/torrc else echo 'ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy managed' >> /etc/tor/torrc fi if grep -q "UseBridges" /etc/tor/torrc; then sed -i 's|#UseBridges|UseBridges|g' /etc/tor/torrc sed -i 's|# UseBridges|UseBridges|g' /etc/tor/torrc sed -i 's|UseBridges.*|UseBridges 1|g' /etc/tor/torrc else echo 'UseBridges 1' >> /etc/tor/torrc fi bridge_str="Bridge $bridge_type ${bridge_ip_address}:${bridge_port} ${bridge_key}" if ! grep -q "${bridge_str}" /etc/tor/torrc; then sed -i "/UseBridges/a ${bridge_str}" >> /etc/tor/torrc 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/tor/torrc; then bridge_str=" ${bridge_ip_address}" else return fi fi if grep -q "${bridge_str}" /etc/tor/torrc; then sed -i "/${bridge_str}/d" /etc/tor/torrc fi # If there are no bridges remaining then remove UseBridges if ! grep -q "Bridge " /etc/tor/torrc; then if ! grep -q "#UseBridges" /etc/tor/torrc; then sed -i 's|UseBridges|#UseBridges|g' /etc/tor/torrc fi if ! grep -q "#ClientTransportPlugin" /etc/tor/torrc; then sed -i 's|ClientTransportPlugin|#ClientTransportPlugin|g' /etc/tor/torrc fi fi systemctl restart tor } function tor_create_bridge_relay { read_config_param 'TOR_BRIDGE_PORT' read_config_param 'TOR_BRIDGE_NICKNAME' 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 apt-get -yq install obfs4proxy sed -i 's|#BridgeRelay.*|BridgeRelay 1|g' /etc/tor/torrc sed -i 's|BridgeRelay.*|BridgeRelay 1|g' /etc/tor/torrc sed -i 's|#ServerTransportPlugin.*|ServerTransportPlugin obfs4 exec /usr/bin/obfs4proxy|g' /etc/tor/torrc sed -i 's|ServerTransportPlugin.*|ServerTransportPlugin obfs4 exec /usr/bin/obfs4proxy|g' /etc/tor/torrc if ! grep -q 'ExtORPort ' /etc/tor/torrc; then echo "ExtORPort $TOR_BRIDGE_PORT" >> /etc/tor/torrc else sed -i "s|#ExtORPort .*|ExtORPort $TOR_BRIDGE_PORT|g" /etc/tor/torrc sed -i "s|ExtORPort .*|ExtORPort $TOR_BRIDGE_PORT|g" /etc/tor/torrc fi read_config_param 'MY_EMAIL_ADDRESS' sed -i "s|#ContactInfo.*|ContactInfo $MY_EMAIL_ADDRESS|g" /etc/tor/torrc if [ $TOR_BRIDGE_NICKNAME ]; then sed -i "s|#Nickname.*|Nickname $TOR_BRIDGE_NICKNAME|g" /etc/tor/torrc sed -i "s|Nickname.*|Nickname $TOR_BRIDGE_NICKNAME|g" /etc/tor/torrc fi firewall_add tor_bridge $TOR_BRIDGE_PORT tcp systemctl restart tor } function tor_remove_bridge_relay { if ! grep -q '#BridgeRelay ' /etc/tor/torrc; then sed -i 's|BridgeRelay |#BridgeRelay |g' /etc/tor/torrc fi if ! grep -q '#ServerTransportPlugin ' /etc/tor/torrc; then sed -i 's|ServerTransportPlugin |#ServerTransportPlugin |g' /etc/tor/torrc fi if ! grep -q '#ExtORPort ' /etc/tor/torrc; then sed -i 's|ExtORPort |#ExtORPort |g' /etc/tor/torrc fi if ! grep -q '#ContactInfo ' /etc/tor/torrc; then sed -i "s|ContactInfo |#ContactInfo |g" /etc/tor/torrc fi if ! grep -q '#Nickname ' /etc/tor/torrc; then sed -i "s|Nickname |#Nickname |g" /etc/tor/torrc fi read_config_param 'TOR_BRIDGE_PORT' firewall_remove $TOR_BRIDGE_PORT tcp systemctl restart tor } # NOTE: deliberately no exit 0