summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tor_extension.php669
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
+ ]
+ ];
+ }
}
-?>