#!/bin/bash

# This file is part of TorBox, an easy to use anonymizing router based on Raspberry Pi.
# Copyright (C) 2026 radio_24
# Contact: anonym@torbox.ch
# Website: https://www.torbox.ch
# Github:  https://github.com/radio24/TorBox
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 is useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# DESCRIPTION
# This file sets all preconditions and defines all iptables rules to route the
# entire data stream from the connected clients through the Tor network.
#
# SYNTAX
# ./set_interfaces_2 <outgoing interface> <incoming interface 1> <incoming interface 2> <incoming interface 3> <captive portal> <only_reset_ip_tables>
#
# The <outgoing interface> is the door to the internet. Possible values for the <outgoing interface>:
# eth0  -> 	TorBox is connected to the Internet with a cable (ethernet interface).
# eth1  -> 	TorBox is connected to the Internet with a cable (USB ethernet adapter) or with a tethering device.
# wlan0 ->  TorBox is connected to the Internet through a wireless network (onboard chip).
# wlan1 -> 	TorBox is connected to the Internet through a wireless network (USB wlan adapter).
# usb0  ->  TorBox is connected to the Internet through an USB adapter or a cellular interface.
# ppp0  ->  TorBox is connected to the Internet through a cellular interface
# tun0  ->  TorBox is connected to the Internet through a VPN server
#
# The <incoming interface 1>, <incoming interface 2> and <incoming interface 3> represent the interfaces where the client-devices
# are connected to the TorBox. Possible values for <incoming interface 1> and <incoming interface 2>:
# eth0  -> 	The device is connected with a cable (ethernet interface).
# eth1  -> 	The device is connected with a cable (USB ethernet adapter).
# wlan0 -> 	The device is connected via wireless network (onboard chip)
# wlan1 -> 	The device is connected via wireless network (USB wlan adapter)
# tun1  ->  The device is a VPN client and connected with TorBox's VPN server (only <incoming interface 3>)
# usb0  ->  The TorBox is a RNDIS/Ethernet Gadget (TorBox mini, only <incoming interface 3>)
#
# Both, <incoming interface 1> and <incoming interface 2>, have to be set.
# If <incoming interface 1> is not used, the default should be "wlan0".
# If <incoming interface 2> is not used, the default should be "eth0", except if the Internet is on "eth0". In this case the default would be "eth1".
#
# Possible values for <captive portal>:
# 0	-> The network connection is open -- no login/password/phone number etc. is required.
# 1	-> To pass through the Captive Portal the TUNNELLING method is used.
# 2 -> To pass through the Captive Portal the SPOOFING method is used.
#
# The <only_reset_ip_tables> is set, if set_interfaces_2 was only called to reset the iptables rules (for example to stop the domains without to exclusion)
# Possible values for <only_reset_ip_tables>:
# 0 -> Default, started after changing the Internet source
# 1 -> Only started to reset the iptables rules
#
###### SET VARIABLES ######

#Colors
RED='\033[1;31m'
YELLOW='\033[1;93m'
NOCOLOR='\033[0m'

#Other variables
IPTABLES="/sbin/iptables"
MODPROBE="/sbin/modprobe"
MY_OWN_IP1="192.168.42.1"
MY_OWN_IP2="192.168.43.1"
MY_OWN_IP3="192.168.44.1"
INT_NET="192.168.0.0/16"
O_DEVICE=$1
I_DEVICE1=$2
I_DEVICE2=$3
I_DEVICE3=$4
CAPTIVE=$5
ONLY_RESET=$6
TORBOX_PATH="/home/torbox/torbox"
RUNFILE="$TORBOX_PATH/run/torbox.run"
EXITLOOP=0

# Network interface ranges
WIFI_NETWORK="192.168.42.0/24"
CABLE_NETWORK="192.168.43.0/24"
USB_VPN_NETWORK="192.168.44.0/24"

#Check if this installation is on a cloud
OPENVPN_PORT=$(grep "^OPENVPN_PORT=.*" ${RUNFILE} | sed "s/.*=//g")
#Can be removed with v.0.5.5
if [ -z "$OPENVPN_PORT" ]; then OPENVPN_PORT="1194"; fi

##############################
######## FUNCTIONS ###########

#include lib
.  /home/torbox/torbox/lib/torbox.lib

# This function pass through Captive Portals using the TUNNELLING nethod
captive_tunneling()
{
	bash $TORBOX_PATH/bin/set_captive_2 $O_DEVICE $I_DEVICE1 $I_DEVICE2 $I_DEVICE3
	EXITLOOP=$?
	if [ $EXITLOOP == 0 ]; then
		echo -e "${RED}[+] Restarting the network...${NOCOLOR}"
		echo ""
		# That should improve the connectivity with the captive portal
		sudo ifdown $O_DEVICE
		# The next line should help TorBox to forget the old IP
		ip addr flush dev $O_DEVICE
		sudo ifup $O_DEVICE &>/dev/null &
		echo ""
		echo -e "${RED}[+] Setting up the interfaces, please wait...${NOCOLOR}"
		echo ""
		if [ "$O_DEVICE" = "wlan0" ] || [ "$O_DEVICE" = "wlan1" ] ; then
			echo -e "${YELLOW}[!] In TWM, please reselect the SSID, to get the latest IP,"
			echo -e "${YELLOW}    even if it shows already an IP!${NOCOLOR}"
			echo ""
		fi
		# NEW v.0.5.4-post
		echo -e "${YELLOW}[+] Step 1 of 2 ...${NOCOLOR}"
		if [ "$O_DEVICE" = "usb0" ]; then
			nohup bin/hostapd_fallback_komplex_new $I_DEVICE1 $I_DEVICE2 notusb0 > /dev/null 2>&1 &
		else
			nohup bin/hostapd_fallback_komplex_new $I_DEVICE1 $I_DEVICE2 > /dev/null 2>&1 &
		fi
		pid=$!
		wait $pid
		echo -e "${YELLOW}[+] Step 2 of 2 done${NOCOLOR}"
		sleep 2
	fi
}

###### ADDITIONAL COMMANDS DEPENDED ON THE INTERFACE CONNECTED TO THE INTERNET ######
while [ $EXITLOOP == 0 ] && [ "$ONLY_RESET" != "1" ]; do
	if [ "$O_DEVICE" = "wlan0" ] || [ "$O_DEVICE" = "wlan1" ]; then
		if [ $CAPTIVE = 2 ]; then
			bash $TORBOX_PATH/bin/change_MAC $O_DEVICE 3
		fi
		clear
		echo -e "${RED}[+] Starting TorBox Wireless Manager...${NOCOLOR}"
		sleep 2
		$TORBOX_PATH/lib/torbox_wireless_manager.py -i $O_DEVICE
		clear
		if [ $CAPTIVE = 1 ]; then
			captive_tunneling
		else
			EXITLOOP=1
		fi
	else
		if [ $CAPTIVE = 2 ]; then
			bash $TORBOX_PATH/bin/change_MAC $O_DEVICE 3
		elif [ $CAPTIVE = 1 ]; then
			captive_tunneling
		else
			EXITLOOP=1
		fi
	fi
done

###### PREPARATIONS ######
clear
echo -e "${RED}[+] Flushing existing iptables rules...${NOCOLOR}"
$IPTABLES -F
$IPTABLES -F -t nat
$IPTABLES -X
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD DROP
$MODPROBE ip_conntrack
$MODPROBE iptable_nat
$MODPROBE ip_conntrack_ftp
$MODPROBE ip_nat_ftp

###### INPUT chain ######
echo -e "${RED}[+] Setting up INPUT chain...${NOCOLOR}"
# State tracking rules
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A INPUT -m state --state INVALID -j DROP
# Anti-spoofing rules
$IPTABLES -A INPUT -i $I_DEVICE1 ! -s $INT_NET -j LOG --log-prefix "SPOOFED PKT "
$IPTABLES -A INPUT -i $I_DEVICE2 ! -s $INT_NET -j LOG --log-prefix "SPOOFED PKT "
$IPTABLES -A INPUT -i $I_DEVICE3 ! -s $INT_NET -j LOG --log-prefix "SPOOFED PKT "
$IPTABLES -A INPUT -i $I_DEVICE1 ! -s $INT_NET -j DROP
$IPTABLES -A INPUT -i $I_DEVICE2 ! -s $INT_NET -j DROP
$IPTABLES -A INPUT -i $I_DEVICE3 ! -s $INT_NET -j DROP
# Let packages to the localhost
$IPTABLES -A INPUT -i lo -j ACCEPT
# Open access from the internal network (usually my own devices)
$IPTABLES -A INPUT -i $I_DEVICE1 -j ACCEPT
$IPTABLES -A INPUT -i $I_DEVICE2 -j ACCEPT
$IPTABLES -A INPUT -i $I_DEVICE3 -j ACCEPT
# Allow ICMP Ping between TorBox and Client
$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
$IPTABLES -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT

###### OUTPUT chain ######
echo -e "${RED}[+] Setting up OUTPUT chain...${NOCOLOR}"
# Avoid Linux kernel transproxy packet leak. See: https://lists.torproject.org/pipermail/tor-talk/2014-March/032507.html
$IPTABLES -A OUTPUT -m conntrack --ctstate INVALID -j DROP
$IPTABLES -A OUTPUT -m state --state INVALID -j DROP
#$IPTABLES -A OUTPUT ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,FIN ACK,FIN -j DROP    --> This rule slows the traffic down and blocks some tools
$IPTABLES -A OUTPUT ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,RST ACK,RST -j DROP
# IMPORTANT: We cannot block local DNS requests!! Meek and Snowflake need local DNS resolution. For more information see here: https://www.torbox.ch/?page_id=112#why-is-the-local-torbox-traffic-not-routed-through-tor-why-is-by-default-googles-andor-cloudflares-service-used-to-circumvent-cheap-censorship-measures-or-to-test-the-connectivity-can-i-change-google-andor-cloudflare-services-with-something-else
# If activated, the rows below will log local DNS requests, but not block them
#$IPTABLES -A OUTPUT -o $O_DEVICE -p tcp --dport 53 -j LOG --log-prefix "SSH SHELL DNS-REQUEST TCP" --log-ip-options --log-tcp-options
#$IPTABLES -A OUTPUT -o $O_DEVICE -p udp --dport 53 -j LOG --log-prefix "SSH SHELL DNS-REQUEST UDP" --log-ip-options
# No other restrictions for OUTPUT

###### FORWARD chain ######
echo -e "${RED}[+] Setting up FORWARD chain...${NOCOLOR}"
# NEW v.0.5.4: Necessary for TorBox on a Cloud --> This rule allows the forwarding of network packets that come in via the Internet-interface and go out via the network- or VPN-interface. The packets have to belong to already established connections or are related to them.
# -i is the interface with the Internet on it / -o is the interface where the clients are connected to the TorBox
$IPTABLES -I FORWARD -i $O_DEVICE -o $I_DEVICE1 -m state --state RELATED,ESTABLISHED -j ACCEPT
$IPTABLES -I FORWARD -i $O_DEVICE -o $I_DEVICE2 -m state --state RELATED,ESTABLISHED -j ACCEPT
$IPTABLES -I FORWARD -i $O_DEVICE -o $I_DEVICE3 -m state --state RELATED,ESTABLISHED -j ACCEPT

# State tracking rules
$IPTABLES -A FORWARD -m state --state INVALID -j DROP
# Allow ICMP Ping --> could compromise anonymity
# $IPTABLES -A FORWARD -p icmp --icmp-type echo-request -j ACCEPT
# $IPTABLES -A FORWARD -p icmp --icmp-type echo-reply -j ACCEPT

###### NAT rules ######
sed -i "s/^FORWARDING_ONLY=.*/FORWARDING_ONLY=0/" ${RUNFILE}
echo -e "${RED}[+] Setting up PREROUTING chain...${NOCOLOR}"
# Access on the box's own IP should be granted (only TCP)
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE1 -d $MY_OWN_IP1 -p tcp -j REDIRECT
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE2 -d $MY_OWN_IP2 -p tcp -j REDIRECT
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE3 -d $MY_OWN_IP3 -p tcp -j REDIRECT
# TCP/UDP/DNS over Tor - Attention: 9053 supports only UDP DNS, the rest goes through 9040!
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE1 -p tcp -j REDIRECT --to-ports 9040
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE2 -p tcp -j REDIRECT --to-ports 9040
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE3 -p tcp -j REDIRECT --to-ports 9040
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE1 -p udp --dport 53 -j REDIRECT --to-ports 9053
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE2 -p udp --dport 53 -j REDIRECT --to-ports 9053
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE3 -p udp --dport 53 -j REDIRECT --to-ports 9053
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE1 -p udp -j REDIRECT --to-ports 9040
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE2 -p udp -j REDIRECT --to-ports 9040
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE3 -p udp -j REDIRECT --to-ports 9040
# NEW v.0.5.4: New log all the rest
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE1 -j LOG --log-prefix "FALLEN THROUGH PREROUTING "
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE2 -j LOG --log-prefix "FALLEN THROUGH PREROUTING "
$IPTABLES -t nat -A PREROUTING -i $I_DEVICE3 -j LOG --log-prefix "FALLEN THROUGH PREROUTING "
# NEW v.0.5.4: This rules would block all the rest. However, there is no rest (see logs)
# Therefore this will only lock ICMP, which creates other problems
# If activated, don't forget to do the same in set_interfaces_3
# $IPTABLES -t nat -A PREROUTING -i $I_DEVICE1 -j DNAT --to-destination 0.0.0.0
# $IPTABLES -t nat -A PREROUTING -i $I_DEVICE2 -j DNAT --to-destination 0.0.0.0
# $IPTABLES -t nat -A PREROUTING -i $I_DEVICE3 -j DNAT --to-destination 0.0.0.0
## Masquerading
$IPTABLES -t nat -A POSTROUTING -o $O_DEVICE -j MASQUERADE

###### SSH access through Internet ######
check_ssh_status
if grep -q "^SSH_FROM_INTERNET=1" ${RUNFILE} ; then
	echo -e "${RED}[+] Setting up SSH access through the Internet...${NOCOLOR}"
	$IPTABLES -A INPUT -p tcp --dport 22 -j ACCEPT
else
	($IPTABLES -D INPUT -p tcp --dport 22 -j ACCEPT) 2>/dev/null
fi

if [ "$SSH_WIFI_STATUS" == "ENABLED" ]; then
	echo -e "${RED}[+] Enabling SSH access from WiFi network...${NOCOLOR}"
	sudo iptables -D INPUT -s $WIFI_NETWORK -p tcp --dport 22 -j DROP 2>/dev/null
else
	echo -e "${RED}[+] Disabling SSH access from WiFi network...${NOCOLOR}"
	sudo iptables -I INPUT 3 -s $WIFI_NETWORK -p tcp --dport 22 -j DROP
fi

if [ "$SSH_CABLE_STATUS" == "ENABLED" ]; then
	echo -e "${RED}[+] Enabling SSH access from cable network...${NOCOLOR}"
	sudo iptables -D INPUT -s $CABLE_NETWORK -p tcp --dport 22 -j DROP 2>/dev/null
else
	echo -e "${RED}[+] Disabling SSH access from cable network...${NOCOLOR}"
	sudo iptables -I INPUT 3 -s $CABLE_NETWORK -p tcp --dport 22 -j DROP
fi

if [ "$SSH_USB_VPN_STATUS" == "ENABLED" ]; then
	echo -e "${RED}[+] Enabling SSH access from USB/VPN network...${NOCOLOR}"
	sudo iptables -D INPUT -s $USB_VPN_NETWORK -p tcp --dport 22 -j DROP 2>/dev/null
else
	echo -e "${RED}[+] Disabling SSH access from USB/VPN network...${NOCOLOR}"
	sudo iptables -I INPUT 3 -s $USB_VPN_NETWORK -p tcp --dport 22 -j DROP
fi

###### OPENVPN access through Internet ######
if grep -q "^OPENVPN_FROM_INTERNET=1" ${RUNFILE} ; then
	echo -e "${RED}[+] Setting up OPENVPN access through the Internet...${NOCOLOR}"
	$IPTABLES -A INPUT -p tcp --dport $OPENVPN_PORT -j ACCEPT
	$IPTABLES -A INPUT -p udp --dport $OPENVPN_PORT -j ACCEPT
	# NEW v.0.5.4-post: OpenVPN fix July 2025 (the -D roule is not necessary)
	$IPTABLES -t nat -I PREROUTING 10 -i $I_DEVICE1 -p udp --dport $OPENVPN_PORT -j ACCEPT
	$IPTABLES -t nat -I PREROUTING 10 -i $I_DEVICE2 -p udp --dport $OPENVPN_PORT -j ACCEPT
	if grep "^TORBOX_MINI=1" ${RUNFILE} ; then $IPTABLES -t nat -I PREROUTING 10 -i $I_DEVICE3 -p udp --dport $OPENVPN_PORT -j ACCEPT; fi
fi

###### HTTP plain text traffic blocker ######
# PREROUTING 3 guaranties that .onion address are not blocked --> set it permanent
if grep -q "^BLOCK_HTTP=1" ${RUNFILE} ; then
	echo -e "${RED}[+] Setting up HTTP plain text traffic blocker...${NOCOLOR}"
	($IPTABLES -t nat -I PREROUTING 4 -p tcp --syn -d 10.192.0.0/10 -j REDIRECT --to-ports 9040) 2>/dev/null
	($IPTABLES -t nat -I PREROUTING 5 -p tcp --dport 80 -j DNAT --to-destination 0.0.0.0) 2>/dev/null
	($IPTABLES -t nat -I PREROUTING 6 -p udp --dport 80 -j DNAT --to-destination 0.0.0.0) 2>/dev/null
else
	($IPTABLES -t nat -D PREROUTING -p tcp --syn -d 10.192.0.0/10 -j REDIRECT --to-ports 9040) 2>/dev/null
	($IPTABLES -t nat -D PREROUTING -p tcp --dport 80 -j DNAT --to-destination 0.0.0.0) 2>/dev/null
	($IPTABLES -t nat -D PREROUTING -p udp --dport 80 -j DNAT --to-destination 0.0.0.0) 2>/dev/null
fi

###### Exclusion of domains from tor protection activated ######
if grep -q "UNPROTECTED_DOMAIN=1" ${RUNFILE} ; then $TORBOX_PATH/bin/set_interfaces_3; fi

###### FINISH ######
# Seems to guarante a more reliable connection for eth0, for example - the question remains whether there are problems with CAPTIVE portals.
# REMARK: Open wlan are disconnected for a second. It seems unproblematic, but this is not sure. Workaround: use the captive portal settings to test.
if [ $CAPTIVE != 1 ] && [ $CAPTIVE != 2 ] && [ "$O_DEVICE" != "ppp0" ]; then
	echo -e "${RED}[+] Finishing...${NOCOLOR}"
	(sudo ifdown $O_DEVICE) 2>/dev/null
	# Test lowered sleep from 2 to 1
	sleep 1
	(sudo ifup $O_DEVICE) 2>/dev/null
	sleep 1
fi
exit 0
