UNPKG

@push.rocks/smartproxy

Version:

A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.

133 lines 10.2 kB
import * as plugins from '../../plugins.js'; import { SniHandler } from '../../tls/sni/sni-handler.js'; import { ProtocolDetector, TlsDetector } from '../../detection/index.js'; /** * Manages TLS-related operations including SNI extraction and validation */ export class TlsManager { constructor(smartProxy) { this.smartProxy = smartProxy; } /** * Check if a data chunk appears to be a TLS handshake */ isTlsHandshake(chunk) { return SniHandler.isTlsHandshake(chunk); } /** * Check if a data chunk appears to be a TLS ClientHello */ isClientHello(chunk) { return SniHandler.isClientHello(chunk); } /** * Extract Server Name Indication (SNI) from TLS handshake */ extractSNI(chunk, connInfo, previousDomain) { // Use the SniHandler to process the TLS packet return SniHandler.processTlsPacket(chunk, connInfo, this.smartProxy.settings.enableTlsDebugLogging || false, previousDomain); } /** * Handle session resumption attempts */ handleSessionResumption(chunk, connectionId, hasSNI) { // Skip if session tickets are allowed if (this.smartProxy.settings.allowSessionTicket !== false) { return { shouldBlock: false }; } // Check for session resumption attempt const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.smartProxy.settings.enableTlsDebugLogging || false); // If this is a resumption attempt without SNI, block it if (resumptionInfo.isResumption && !hasSNI && !resumptionInfo.hasSNI) { if (this.smartProxy.settings.enableTlsDebugLogging) { console.log(`[${connectionId}] Session resumption detected without SNI and allowSessionTicket=false. ` + `Terminating connection to force new TLS handshake.`); } return { shouldBlock: true, reason: 'session_ticket_blocked' }; } return { shouldBlock: false }; } /** * Check for SNI mismatch during renegotiation */ checkRenegotiationSNI(chunk, connInfo, expectedDomain, connectionId) { // Only process if this looks like a TLS ClientHello if (!this.isClientHello(chunk)) { return { hasMismatch: false }; } try { // Extract SNI with renegotiation support const newSNI = SniHandler.extractSNIWithResumptionSupport(chunk, connInfo, this.smartProxy.settings.enableTlsDebugLogging || false); // Skip if no SNI was found if (!newSNI) return { hasMismatch: false }; // Check for SNI mismatch if (newSNI !== expectedDomain) { if (this.smartProxy.settings.enableTlsDebugLogging) { console.log(`[${connectionId}] Renegotiation with different SNI: ${expectedDomain} -> ${newSNI}. ` + `Terminating connection - SNI domain switching is not allowed.`); } return { hasMismatch: true, extractedSNI: newSNI }; } else if (this.smartProxy.settings.enableTlsDebugLogging) { console.log(`[${connectionId}] Renegotiation detected with same SNI: ${newSNI}. Allowing.`); } } catch (err) { console.log(`[${connectionId}] Error processing ClientHello: ${err}. Allowing connection to continue.`); } return { hasMismatch: false }; } /** * Create a renegotiation handler function for a connection */ createRenegotiationHandler(connectionId, lockedDomain, connInfo, onMismatch) { return (chunk) => { const result = this.checkRenegotiationSNI(chunk, connInfo, lockedDomain, connectionId); if (result.hasMismatch) { onMismatch(connectionId, 'sni_mismatch'); } }; } /** * Analyze TLS connection for browser fingerprinting * This helps identify browser vs non-browser connections */ analyzeClientHello(chunk) { // Default result const result = { isBrowserConnection: false, isRenewal: false, hasSNI: false }; try { // Check if it's a ClientHello if (!this.isClientHello(chunk)) { return result; } // Check for session resumption const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.smartProxy.settings.enableTlsDebugLogging || false); // Extract SNI const sni = SniHandler.extractSNI(chunk, this.smartProxy.settings.enableTlsDebugLogging || false); // Update result result.isRenewal = resumptionInfo.isResumption; result.hasSNI = !!sni; // Browsers typically: // 1. Send SNI extension // 2. Have a variety of extensions (ALPN, etc.) // 3. Use standard cipher suites // ...more complex heuristics could be implemented here // Simple heuristic: presence of SNI suggests browser result.isBrowserConnection = !!sni; return result; } catch (err) { console.log(`Error analyzing ClientHello: ${err}`); return result; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGxzLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3Rscy1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzFELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQWF6RTs7R0FFRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBQ3JCLFlBQW9CLFVBQXNCO1FBQXRCLGVBQVUsR0FBVixVQUFVLENBQVk7SUFBRyxDQUFDO0lBRTlDOztPQUVHO0lBQ0ksY0FBYyxDQUFDLEtBQWE7UUFDakMsT0FBTyxVQUFVLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRDs7T0FFRztJQUNJLGFBQWEsQ0FBQyxLQUFhO1FBQ2hDLE9BQU8sVUFBVSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxVQUFVLENBQ2YsS0FBYSxFQUNiLFFBQXlCLEVBQ3pCLGNBQXVCO1FBRXZCLCtDQUErQztRQUMvQyxPQUFPLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FDaEMsS0FBSyxFQUNMLFFBQVEsRUFDUixJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsSUFBSSxLQUFLLEVBQ3ZELGNBQWMsQ0FDZixDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0ksdUJBQXVCLENBQzVCLEtBQWEsRUFDYixZQUFvQixFQUNwQixNQUFlO1FBRWYsc0NBQXNDO1FBQ3RDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsa0JBQWtCLEtBQUssS0FBSyxFQUFFLENBQUM7WUFDMUQsT0FBTyxFQUFFLFdBQVcsRUFBRSxLQUFL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