#!/bin/bash ################################################################################ # TOR Health Monitoring Script # # Purpose: Continuous monitoring of TOR connectivity and TeleBot TOR usage # Usage: ./tor-health-monitor.sh [--daemon] [--interval=60] # Output: Health reports and alerts # # Features: # - Real-time TOR connectivity monitoring # - Circuit health tracking # - IP leak detection # - Automated alerting # - Historical logging # # Author: Mr Tickles, Security Consultant # Date: 2025-10-01 ################################################################################ set -euo pipefail # Configuration INTERVAL=60 # Check interval in seconds DAEMON_MODE=false LOG_DIR="/var/log/telebot" HEALTH_LOG="$LOG_DIR/tor-health.log" ALERT_LOG="$LOG_DIR/tor-alerts.log" STATE_DIR="/var/lib/telebot" TOR_SOCKS_PORT=9050 EMAIL_ALERTS=false ALERT_EMAIL="admin@example.com" # Parse arguments for arg in "$@"; do case $arg in --daemon) DAEMON_MODE=true shift ;; --interval=*) INTERVAL="${arg#*=}" shift ;; --email=*) ALERT_EMAIL="${arg#*=}" EMAIL_ALERTS=true shift ;; *) ;; esac done # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # Create directories mkdir -p "$LOG_DIR" "$STATE_DIR" ################################################################################ # Logging Functions ################################################################################ log() { local level=$1 shift local message="$@" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] [$level] $message" >> "$HEALTH_LOG" if [ "$DAEMON_MODE" = false ]; then case $level in INFO) echo -e "${BLUE}[INFO]${NC} $message" ;; SUCCESS) echo -e "${GREEN}[✓]${NC} $message" ;; WARNING) echo -e "${YELLOW}[⚠]${NC} $message" ;; ERROR) echo -e "${RED}[✗]${NC} $message" ;; ALERT) echo -e "${RED}[ALERT]${NC} $message" echo "[$timestamp] [ALERT] $message" >> "$ALERT_LOG" ;; esac fi } send_alert() { local subject="$1" local message="$2" log ALERT "$subject: $message" if [ "$EMAIL_ALERTS" = true ]; then echo "$message" | mail -s "TeleBot TOR Alert: $subject" "$ALERT_EMAIL" 2>/dev/null || true fi } ################################################################################ # Health Check Functions ################################################################################ check_tor_service() { if systemctl is-active --quiet tor 2>/dev/null; then log SUCCESS "TOR service is running" return 0 else log ERROR "TOR service is not running" send_alert "TOR Service Down" "TOR service is not running. TeleBot location is EXPOSED!" return 1 fi } check_tor_socks() { if netstat -tln 2>/dev/null | grep -q ":${TOR_SOCKS_PORT} "; then log SUCCESS "TOR SOCKS5 proxy is listening on port ${TOR_SOCKS_PORT}" return 0 else log ERROR "TOR SOCKS5 proxy is not listening" send_alert "TOR SOCKS5 Down" "TOR SOCKS5 proxy not available. Traffic cannot be routed through TOR!" return 1 fi } check_tor_circuits() { local bootstrap_status=$(journalctl -u tor -n 100 --no-pager 2>/dev/null | \ grep -i "Bootstrapped" | tail -1) if echo "$bootstrap_status" | grep -q "100%"; then log SUCCESS "TOR circuits are established (100%)" return 0 else log WARNING "TOR circuits may not be fully established" return 1 fi } check_tor_ip() { local tor_ip="" local direct_ip="" # Get IP through TOR tor_ip=$(timeout 15 curl --socks5 127.0.0.1:${TOR_SOCKS_PORT} -s https://api.ipify.org 2>/dev/null || echo "") if [ -z "$tor_ip" ]; then log ERROR "Failed to get IP through TOR" return 1 fi # Get direct IP direct_ip=$(timeout 10 curl -s https://api.ipify.org 2>/dev/null || echo "") if [ -z "$direct_ip" ]; then log WARNING "Failed to get direct IP (network issue?)" return 0 fi # Compare IPs if [ "$tor_ip" != "$direct_ip" ]; then log SUCCESS "TOR IP ($tor_ip) is different from direct IP ($direct_ip)" # Save IPs for tracking echo "$tor_ip" > "$STATE_DIR/current_tor_ip" echo "$direct_ip" > "$STATE_DIR/real_ip" return 0 else log ERROR "TOR IP matches direct IP - TOR may not be working!" send_alert "TOR IP Mismatch" "TOR IP ($tor_ip) matches direct IP! TOR may be bypassed!" return 1 fi } check_telebot_process() { if pgrep -f "TeleBot" > /dev/null; then local pid=$(pgrep -f "TeleBot" | head -1) log SUCCESS "TeleBot is running (PID: $pid)" # Check TOR connections local tor_conns=$(lsof -p "$pid" -i TCP 2>/dev/null | grep -c ":${TOR_SOCKS_PORT}" || echo 0) if [ "$tor_conns" -gt 0 ]; then log SUCCESS "TeleBot has $tor_conns active TOR connections" else log WARNING "TeleBot has no active TOR connections" fi return 0 else log WARNING "TeleBot is not running" return 1 fi } check_ip_leaks() { if ! pgrep -f "TeleBot" > /dev/null; then return 0 # Can't check if not running fi local pid=$(pgrep -f "TeleBot" | head -1) # Check for direct external connections local external_conns=$(ss -tnp 2>/dev/null | grep "$pid" | \ grep -v "127.0.0.1" | \ grep -v "::1" | \ grep -v ":${TOR_SOCKS_PORT}" | \ wc -l) if [ "$external_conns" -eq 0 ]; then log SUCCESS "No IP leaks detected (all connections through TOR)" return 0 else log ERROR "Detected $external_conns direct external connections - IP LEAK!" send_alert "IP Leak Detected" "TeleBot has $external_conns direct external connections not through TOR!" # Log the suspicious connections ss -tnp 2>/dev/null | grep "$pid" | \ grep -v "127.0.0.1" | \ grep -v "::1" | \ grep -v ":${TOR_SOCKS_PORT}" >> "$ALERT_LOG" return 1 fi } check_dns_leaks() { # Monitor for DNS queries not through TOR local dns_count=$(timeout 5 tcpdump -i any -c 10 'port 53' 2>/dev/null | wc -l || echo 0) if [ "$dns_count" -eq 0 ]; then log SUCCESS "No DNS leaks detected" return 0 else log WARNING "Detected DNS queries - potential DNS leak" return 1 fi } ################################################################################ # Performance Metrics ################################################################################ measure_tor_latency() { local start_time=$(date +%s%N) local test_result=$(timeout 10 curl --socks5 127.0.0.1:${TOR_SOCKS_PORT} -s -o /dev/null -w "%{http_code}" https://check.torproject.org 2>/dev/null || echo "0") local end_time=$(date +%s%N) if [ "$test_result" = "200" ]; then local latency=$(( (end_time - start_time) / 1000000 )) # Convert to milliseconds log INFO "TOR latency: ${latency}ms" echo "$latency" > "$STATE_DIR/tor_latency" if [ "$latency" -gt 5000 ]; then log WARNING "TOR latency is high (${latency}ms)" fi return 0 else log ERROR "Failed to measure TOR latency" return 1 fi } ################################################################################ # Main Health Check ################################################################################ run_health_check() { local check_id=$(date +%Y%m%d_%H%M%S) log INFO "==================== Health Check $check_id ====================" local total_checks=0 local passed_checks=0 # Run all checks for check in check_tor_service check_tor_socks check_tor_circuits \ check_tor_ip check_telebot_process check_ip_leaks \ check_dns_leaks measure_tor_latency; do total_checks=$((total_checks + 1)) if $check; then passed_checks=$((passed_checks + 1)) fi done # Calculate health score local health_score=$((passed_checks * 100 / total_checks)) log INFO "Health Score: $health_score% ($passed_checks/$total_checks checks passed)" # Save health score echo "$health_score" > "$STATE_DIR/health_score" # Alert if health is poor if [ "$health_score" -lt 80 ]; then send_alert "Poor Health Score" "TOR health score is $health_score%. Review logs: $HEALTH_LOG" fi log INFO "================================================================" echo "" } ################################################################################ # Daemon Mode ################################################################################ run_daemon() { log INFO "Starting TOR health monitor daemon (interval: ${INTERVAL}s)" # Create PID file echo $$ > "$STATE_DIR/monitor.pid" # Trap signals trap 'log INFO "Stopping TOR health monitor daemon"; rm -f "$STATE_DIR/monitor.pid"; exit 0' SIGTERM SIGINT while true; do run_health_check sleep "$INTERVAL" done } ################################################################################ # Main ################################################################################ main() { if [ "$DAEMON_MODE" = true ]; then run_daemon else run_health_check fi } # Execute main "$@"