diff options
Diffstat (limited to 'tor_extension.php')
| -rw-r--r-- | tor_extension.php | 669 |
1 files changed, 283 insertions, 386 deletions
diff --git a/tor_extension.php b/tor_extension.php index 9611cad..4c18f9f 100644 --- a/tor_extension.php +++ b/tor_extension.php @@ -1,445 +1,342 @@ <?php /** - * Secure Tor Extension for YAMN Web Interface - * - * Security Features: - * - No metadata retention (no detailed logging) - * - Randomized timing delays - * - Secure command execution - * - Tor enforcement with verification - * - Protection against timing attacks - * - * This implementation follows privacy-first principles + * Tor Extension for YAMN Web Interface + * Handles Tor integration for anonymous remailer network */ // Constants define('YAMN_PATH', '/opt/yamn-master/yamn'); -define('YAMN_CONFIG', '/opt/yamn-master/yamn.yml'); +define('YAMN_CONFIG', '/opt/yamn-master/yamn.cfg'); define('TOR_PROXY', '127.0.0.1:9050'); +define('TOR_CONFIG_FILE', '/var/www/yamnweb/tor_config.ini'); define('TORSOCKS_PATH', 'torsocks'); -define('SECURE_POOL_DIR', '/opt/yamn-data/pool'); + +// SMTP Onion Relays - Primary and Fallback +define('SMTP_RELAYS', [ + [ + 'host' => '4uwpi53u524xdphjw2dv5kywsxmyjxtk4facb76jgl3sc3nda3sz4fqd.onion', + 'port' => 25, + 'name' => 'Primary Onion SMTP' + ], + [ + 'host' => 'xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion', + 'port' => 25, + 'name' => 'Fallback Onion SMTP' + ] +]); + +/** + * Debug logger function + * + * @param string $message Message to log + * @param bool $include_timestamp Whether to include timestamp + * @return void + */ +function logDebug($message, $include_timestamp = true) { + $log_file = '/var/www/yamnweb/debug.log'; + $log_entry = ($include_timestamp ? date('Y-m-d H:i:s') . " - " : "") . $message . "\n"; + file_put_contents($log_file, $log_entry, FILE_APPEND); +} /** - * Check if Tor is available and working - * - * @return bool True if Tor is available + * Check if Tor is available on the system + * + * @return bool True if Tor service is available */ function isTorAvailable() { + logDebug("Checking if Tor is available..."); + // Check if torsocks is installed - $torsocksPath = shell_exec('which torsocks 2>/dev/null'); - if (empty($torsocksPath)) { - return false; + $torsocks_check = shell_exec('which torsocks 2>&1'); + if (empty($torsocks_check) || strpos($torsocks_check, 'no torsocks') !== false) { + logDebug("WARNING: torsocks not found in PATH. Tor routing may not work correctly."); + } else { + logDebug("torsocks found: " . trim($torsocks_check)); } - + // Check if Tor SOCKS proxy is listening - $connection = @fsockopen('127.0.0.1', 9050, $errno, $errstr, 2); - if (!is_resource($connection)) { - return false; + $connection = @fsockopen('127.0.0.1', 9050, $errno, $errstr, 1); + if (is_resource($connection)) { + fclose($connection); + logDebug("Tor is available: SOCKS proxy connection successful"); + return true; } - - fclose($connection); - - // Verify Tor by checking external IP through Tor - // This ensures Tor is actually working, not just listening - $ch = curl_init(); - curl_setopt_array($ch, [ - CURLOPT_URL => 'https://check.torproject.org/api/ip', - CURLOPT_RETURNTRANSFER => true, - CURLOPT_PROXY => '127.0.0.1:9050', - CURLOPT_PROXYTYPE => CURLPROXY_SOCKS5_HOSTNAME, - CURLOPT_TIMEOUT => 30, - CURLOPT_SSL_VERIFYPEER => true - ]); - - $result = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - - if ($httpCode === 200 && $result) { - $data = json_decode($result, true); - return isset($data['IsTor']) && $data['IsTor'] === true; + + logDebug("SOCKS proxy connection failed: $errno - $errstr"); + + // Alternative: Check if Tor service is running + $tor_running = shell_exec('pgrep -f "tor" | wc -l'); + if (intval($tor_running) > 0) { + logDebug("Tor is available: Tor process is running"); + return true; } - - return false; -} -/** - * Secure random delay to prevent timing correlation - * - * @param int $minSeconds Minimum delay in seconds - * @param int $maxSeconds Maximum delay in seconds - */ -function secureRandomDelay($minSeconds = 10, $maxSeconds = 120) { - $delay = random_int($minSeconds, $maxSeconds); - sleep($delay); + logDebug("Tor is NOT available: No Tor process found"); + return false; } /** - * Validate remailer chain to prevent injection - * - * @param string $chain The remailer chain - * @return bool True if valid + * Check if an email address belongs to an .onion domain + * + * @param string $email The email address to check + * @return bool True if the email is for an .onion domain */ -function isValidChain($chain) { - // Chain should only contain alphanumeric, comma, asterisk, and hyphen - return preg_match('/^[a-zA-Z0-9,\*\-]+$/', $chain) === 1; +function isOnionEmail($email) { + // Extract domain from email address + if (preg_match('/@([^>]+)/', $email, $matches)) { + $domain = $matches[1]; + $is_onion = (strpos($domain, '.onion') !== false); + logDebug("Email domain check: $domain - " . ($is_onion ? "is .onion" : "is NOT .onion")); + return $is_onion; + } + logDebug("No domain found in email: $email"); + return false; } /** - * Secure command execution with proper escaping - * - * @param string $command Command to execute - * @param array &$output Output array - * @param int &$returnVar Return code + * Determine if Tor should be used for the current email + * + * @param string $to The recipient email address + * @return bool True if Tor should be used */ -function secureExec($command, &$output, &$returnVar) { - // Execute with output buffering - exec($command, $output, $returnVar); -} +function shouldUseTor($to) { + logDebug("Checking if Tor should be used for recipient: $to"); -/** - * Send email through YAMN with Tor (always enforced) - * - * @param string $chain Remailer chain - * @param int $copies Number of copies - * @param string $messageFile Path to message file - * @param bool $useTor Ignored, Tor is always used - * @return array Result status - */ -function sendYamnEmailSecure($chain, $copies, $messageFile, $useTor = true) { - // Validate inputs - if (!isValidChain($chain)) { - return [ - 'success' => false, - 'errors' => ['Invalid remailer chain format'] - ]; - } - - if ($copies < 1 || $copies > 3) { - return [ - 'success' => false, - 'errors' => ['Invalid number of copies'] - ]; - } - - // Verify prerequisites - if (!file_exists($messageFile)) { - return [ - 'success' => false, - 'errors' => ['Message file not found'] - ]; + // Use Tor if the destination is an .onion address + if (isOnionEmail($to)) { + logDebug("Tor will be used: .onion address detected"); + return true; } - - if (!file_exists(YAMN_PATH) || !is_executable(YAMN_PATH)) { - return [ - 'success' => false, - 'errors' => ['YAMN executable not available'] - ]; - } - - if (!file_exists(YAMN_CONFIG)) { - return [ - 'success' => false, - 'errors' => ['YAMN configuration not found'] - ]; - } - - // Verify torsocks is available - $torsocksCheck = shell_exec('which torsocks 2>/dev/null'); - if (empty($torsocksCheck)) { - return [ - 'success' => false, - 'errors' => ['torsocks not installed'] - ]; - } - - // Random delay BEFORE adding to pool (prevent timing correlation) - secureRandomDelay(5, 30); - - // Escape arguments properly - $escapedChain = escapeshellarg($chain); - $escapedCopies = (int)$copies; - $escapedMessageFile = escapeshellarg($messageFile); - $escapedYamnPath = escapeshellarg(YAMN_PATH); - $escapedConfig = escapeshellarg(YAMN_CONFIG); - - // Build command with proper escaping - // Use process substitution to avoid leaving message file readable - $commandAddToPool = sprintf( - '%s %s --config=%s --mail --chain=%s --copies=%d 2>&1 < %s', - TORSOCKS_PATH, - $escapedYamnPath, - $escapedConfig, - $escapedChain, - $escapedCopies, - $escapedMessageFile - ); - - // Execute add to pool - $outputAddToPool = []; - $returnVarAddToPool = 0; - secureExec($commandAddToPool, $outputAddToPool, $returnVarAddToPool); - - // Check if add to pool succeeded - if ($returnVarAddToPool !== 0) { - return [ - 'success' => false, - 'errors' => ['Failed to add message to pool'] - ]; + + // Use Tor if forced by configuration file + if (file_exists(TOR_CONFIG_FILE)) { + logDebug("Config file exists: " . TOR_CONFIG_FILE); + $config = parse_ini_file(TOR_CONFIG_FILE, true); + if (isset($config['tor']) && isset($config['tor']['force_tor'])) { + $force_tor = ($config['tor']['force_tor'] === 'true' || $config['tor']['force_tor'] === '1'); + logDebug("Config file force_tor setting: " . ($force_tor ? "true" : "false")); + return $force_tor; + } } - - // Random delay BETWEEN operations - secureRandomDelay(3, 15); - - // Build send command - $commandSend = sprintf( - '%s %s --config=%s -S 2>&1', - TORSOCKS_PATH, - $escapedYamnPath, - $escapedConfig - ); - - // Execute send - $outputSend = []; - $returnVarSend = 0; - secureExec($commandSend, $outputSend, $returnVarSend); - - // Determine success - $success = ($returnVarSend === 0 && $returnVarAddToPool === 0); - - // Random delay AFTER sending (prevent timing correlation) - secureRandomDelay(2, 10); - - // Return minimal information (no detailed logs) - if ($success) { - return [ - 'success' => true - ]; - } else { - return [ - 'success' => false, - 'errors' => ['Failed to send message'] - ]; + + // Check environment variables + $force_tor_env = getenv('YAMN_TOR_FORCE'); + if ($force_tor_env) { + $result = ($force_tor_env === 'true' || $force_tor_env === '1'); + logDebug("Environment variable YAMN_TOR_FORCE: " . ($result ? "true" : "false")); + return $result; } -} -/** - * Legacy wrapper for backward compatibility - * Always uses Tor regardless of $useTor parameter - */ -function sendYamnEmail($chain, $copies, $messageFile, $useTor = true) { - return sendYamnEmailSecure($chain, $copies, $messageFile, true); + logDebug("Tor will NOT be used: No .onion address or force settings"); + return false; } /** - * Verify Tor circuit and get new identity - * Useful before sending to ensure fresh circuit - * - * @return bool True if successful + * Configure Tor environment settings for YAMN + * + * @param bool $useTor Whether to force Tor usage + * @return void */ -function getTorNewIdentity() { - // Connect to Tor control port - $fp = @fsockopen('127.0.0.1', 9051, $errno, $errstr, 5); - if (!$fp) { - return false; - } - - // Authenticate (assuming no password or cookie auth) - // In production, use proper authentication - fwrite($fp, "AUTHENTICATE\r\n"); - $response = fgets($fp); - - if (strpos($response, '250') === false) { - fclose($fp); - return false; +function configureTorForYamn($useTor = false) { + if ($useTor) { + logDebug("Configuring Tor environment variables"); + + // Set SOCKS proxy environment variables + putenv("SOCKS_PROXY=" . TOR_PROXY); + putenv("ALL_PROXY=socks5://" . TOR_PROXY); + putenv("socks_proxy=" . TOR_PROXY); + putenv("all_proxy=socks5://" . TOR_PROXY); + putenv("YAMN_USE_TOR=1"); + putenv("YAMN_TOR_ENABLED=true"); + putenv("YAMN_TOR_FORCE=true"); + + logDebug("Tor environment configured with proxy: " . TOR_PROXY); + } else { + logDebug("Clearing Tor environment variables"); + + // Clear environment variables when not using Tor + putenv("SOCKS_PROXY="); + putenv("ALL_PROXY="); + putenv("socks_proxy="); + putenv("all_proxy="); + putenv("YAMN_USE_TOR=0"); + putenv("YAMN_TOR_ENABLED=false"); + putenv("YAMN_TOR_FORCE=false"); } - - // Request new identity - fwrite($fp, "SIGNAL NEWNYM\r\n"); - $response = fgets($fp); - - fclose($fp); - - return strpos($response, '250') !== false; } /** - * Enhanced Tor check with circuit verification - * - * @return bool True if Tor is working properly + * Test SMTP relay connectivity through Tor + * + * @param string $host SMTP relay hostname + * @param int $port SMTP port + * @return bool True if relay is reachable */ -function verifyTorCircuit() { - // Check basic Tor availability - if (!isTorAvailable()) { - return false; - } - - // Try to get a new circuit - // This ensures Tor is not just running but actually functional - if (!getTorNewIdentity()) { - // If we can't get new identity, Tor might still work - // Don't fail, just continue - } - - // Wait a moment for circuit to build - sleep(2); - - return true; +function testSmtpRelay($host, $port) { + logDebug("Testing SMTP relay: $host:$port"); + + // Use torsocks to test connection through Tor + $command = "timeout 10 torsocks nc -zv $host $port 2>&1"; + exec($command, $output, $return_var); + + $success = ($return_var == 0); + logDebug("SMTP relay test result: " . ($success ? "SUCCESS" : "FAILED")); + logDebug("Test output: " . implode(" ", $output)); + + return $success; } /** - * Initialize secure environment for YAMN operations - * - * @return bool True if successful + * Update YAMN config with specific SMTP relay + * VERSIONE DISABILITATA - Non modifica il file, usa configurazione statica + * + * @param string $host SMTP relay hostname + * @param int $port SMTP port + * @return bool True if update successful */ -function initSecureEnvironment() { - // Ensure secure directories exist - if (!file_exists(SECURE_POOL_DIR)) { - mkdir(SECURE_POOL_DIR, 0700, true); - } - - // Set restrictive umask - umask(0077); - - // Verify Tor is available - if (!isTorAvailable()) { +function updateYamnConfig($host, $port) { + logDebug("Config update DISABLED - using static configuration"); + logDebug("Requested relay: $host:$port (will be ignored, using config file as-is)"); + + // Verifica solo che il file esista + if (!file_exists(YAMN_CONFIG)) { + logDebug("ERROR: Config file not found: " . YAMN_CONFIG); return false; } - + + logDebug("Config file exists, skipping dynamic update"); return true; } /** - * Clean up function to be called after operations - * Removes temporary files securely - * - * @param string $filepath File to securely delete + * Send an email through YAMN with optional Tor routing and automatic fallback + * + * @param string $chain The remailer chain string (e.g., "entry,middle,exit") + * @param int $copies Number of copies to send (1-3) + * @param string $messageFile Path to the message file + * @param bool $useTor Whether to force Tor usage + * @return array Array containing success status, error message, and output */ -function secureCleanup($filepath) { - if (!file_exists($filepath)) { - return; - } - - $filesize = filesize($filepath); - - // DoD 5220.22-M standard: 3-pass overwrite - for ($i = 0; $i < 3; $i++) { - $fp = fopen($filepath, 'w'); - if ($fp) { - fwrite($fp, random_bytes($filesize)); - fclose($fp); - } - } - - // Final overwrite with zeros - $fp = fopen($filepath, 'w'); - if ($fp) { - fwrite($fp, str_repeat("\0", $filesize)); - fclose($fp); - } - - // Delete file - unlink($filepath); -} +function sendYamnEmail($chain, $copies, $messageFile, $useTor = false) { + logDebug("=== Starting sendYamnEmail (Static Config Mode) ==="); + logDebug("Chain: $chain"); + logDebug("Copies: $copies"); + logDebug("Message file: $messageFile"); + logDebug("Use Tor: " . ($useTor ? "YES" : "NO")); -/** - * Get Tor circuit information (for debugging only) - * DO NOT use in production as it may leak information - * - * @return array|false Circuit info or false - */ -function getTorCircuitInfo() { - // Only enable if explicitly requested via environment variable - if (getenv('YAMN_DEBUG_TOR') !== 'true') { - return false; - } - - $fp = @fsockopen('127.0.0.1', 9051, $errno, $errstr, 5); - if (!$fp) { - return false; - } - - fwrite($fp, "AUTHENTICATE\r\n"); - $response = fgets($fp); - - if (strpos($response, '250') === false) { - fclose($fp); - return false; + // Configure environment for YAMN to use Tor if needed + configureTorForYamn($useTor); + + // Check if message file exists + if (!file_exists($messageFile)) { + $error = "Message file does not exist: $messageFile"; + logDebug("ERROR: $error"); + return [ + 'success' => false, + 'error' => $error, + 'relay_used' => null, + 'output' => [] + ]; } - - fwrite($fp, "GETINFO circuit-status\r\n"); - $response = ''; - while (!feof($fp)) { - $line = fgets($fp); - $response .= $line; - if (strpos($line, '250 OK') !== false) { - break; - } + + // Verifica che il config file esista + if (!file_exists(YAMN_CONFIG)) { + $error = "Config file does not exist: " . YAMN_CONFIG; + logDebug("ERROR: $error"); + return [ + 'success' => false, + 'error' => $error, + 'relay_used' => null, + 'output' => [] + ]; } - - fclose($fp); - - return ['circuit_status' => $response]; -} -/** - * Test Tor connectivity without leaving traces - * - * @return array Test results - */ -function testTorConnectivity() { - $results = [ - 'tor_available' => false, - 'socks_proxy' => false, - 'circuit_working' => false, - 'torsocks_installed' => false - ]; - - // Check SOCKS proxy - $connection = @fsockopen('127.0.0.1', 9050, $errno, $errstr, 2); - if (is_resource($connection)) { - $results['socks_proxy'] = true; - fclose($connection); + // Build YAMN command to add message to pool + $command_add_to_pool = YAMN_PATH . " " . + "--config=" . YAMN_CONFIG . " " . + "--mail " . + "--chain=\"$chain\" " . + "--copies=$copies < " . escapeshellarg($messageFile) . " 2>&1"; + + // Command to send emails in pool + $command_send = YAMN_PATH . " " . + "--config=" . YAMN_CONFIG . " -S 2>&1"; + + // Log the commands + logDebug("Add to pool command: $command_add_to_pool"); + + // Execute add to pool command + logDebug("Executing add to pool command..."); + exec($command_add_to_pool, $output_add_to_pool, $return_var_add_to_pool); + + // Log the output and return code + logDebug("Add to pool output: " . implode("\n", $output_add_to_pool)); + logDebug("Add to pool return code: $return_var_add_to_pool"); + + // Initialize send variables + $output_send = []; + $return_var_send = -1; + + // Only execute send command if add to pool was successful + if ($return_var_add_to_pool == 0) { + logDebug("Send command: $command_send"); + logDebug("Executing send command..."); + exec($command_send, $output_send, $return_var_send); + logDebug("Send output: " . implode("\n", $output_send)); + logDebug("Send return code: $return_var_send"); + } else { + logDebug("Skipping send command due to add to pool failure"); + $output_send = ["Skipped - add to pool command failed"]; + $return_var_send = -1; } - - // Check torsocks - $torsocksPath = shell_exec('which torsocks 2>/dev/null'); - $results['torsocks_installed'] = !empty($torsocksPath); - - // Check if Tor is actually working - $ch = curl_init(); - curl_setopt_array($ch, [ - CURLOPT_URL => 'https://check.torproject.org/api/ip', - CURLOPT_RETURNTRANSFER => true, - CURLOPT_PROXY => '127.0.0.1:9050', - CURLOPT_PROXYTYPE => CURLPROXY_SOCKS5_HOSTNAME, - CURLOPT_TIMEOUT => 15, - CURLOPT_SSL_VERIFYPEER => true - ]); - - $result = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - - if ($httpCode === 200 && $result) { - $data = json_decode($result, true); - if (isset($data['IsTor']) && $data['IsTor'] === true) { - $results['circuit_working'] = true; + + // Check if succeeded + $success = ($return_var_send == 0 && $return_var_add_to_pool == 0); + + if ($success) { + // SUCCESS! Log and return + $log_entry = date('Y-m-d H:i:s') . " | SUCCESS | Chain: $chain | Copies: $copies | Tor: " . + ($useTor ? "Yes" : "No") . "\n"; + file_put_contents('/var/www/yamnweb/yamn_send.log', $log_entry, FILE_APPEND); + + logDebug("✓ SUCCESS"); + logDebug("=== End sendYamnEmail ==="); + + return [ + 'success' => true, + 'error' => '', + 'relay_used' => 'Static Config', + 'tor_used' => $useTor, + 'outputs' => [ + 'add_to_pool' => $output_add_to_pool, + 'send' => $output_send + ] + ]; + } else { + // Failed + $lastError = "Failed to send message"; + if ($return_var_add_to_pool != 0) { + $lastError = "Failed to add message to pool: " . implode(" ", $output_add_to_pool); + } elseif ($return_var_send != 0) { + $lastError = "Failed to send from pool: " . implode(" ", $output_send); } - } - - $results['tor_available'] = ( - $results['socks_proxy'] && - $results['torsocks_installed'] && - $results['circuit_working'] - ); - - return $results; -} -// Initialize on load -if (!initSecureEnvironment()) { - // Silent fail - don't leak information - // In production, handle this appropriately + $log_entry = date('Y-m-d H:i:s') . " | FAILED | Chain: $chain | Copies: $copies | Tor: " . + ($useTor ? "Yes" : "No") . " | Error: $lastError\n"; + file_put_contents('/var/www/yamnweb/yamn_send.log', $log_entry, FILE_APPEND); + + logDebug("✗ FAILED: $lastError"); + logDebug("=== End sendYamnEmail ==="); + + return [ + 'success' => false, + 'error' => $lastError, + 'relay_used' => null, + 'tor_used' => $useTor, + 'outputs' => [ + 'add_to_pool' => $output_add_to_pool, + 'send' => $output_send + ] + ]; + } } -?> |
