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.

183 lines 12.9 kB
/** * TLS protocol detector */ import { readUInt16BE } from '../utils/buffer-utils.js'; import { tlsVersionToString } from '../utils/parser-utils.js'; // Import from protocols import { TlsRecordType, TlsHandshakeType, TlsExtensionType } from '../../protocols/tls/index.js'; // Import TLS utilities for SNI extraction from protocols import { SniExtraction } from '../../protocols/tls/sni/sni-extraction.js'; import { ClientHelloParser } from '../../protocols/tls/sni/client-hello-parser.js'; /** * TLS detector implementation */ export class TlsDetector { /** * Minimum bytes needed to identify TLS (record header) */ static { this.MIN_TLS_HEADER_SIZE = 5; } /** * Detect TLS protocol from buffer */ detect(buffer, options) { // Check if buffer is too small if (buffer.length < TlsDetector.MIN_TLS_HEADER_SIZE) { return null; } // Check if this is a TLS record if (!this.isTlsRecord(buffer)) { return null; } // Extract basic TLS info const recordType = buffer[0]; const tlsMajor = buffer[1]; const tlsMinor = buffer[2]; const recordLength = readUInt16BE(buffer, 3); // Initialize connection info const connectionInfo = { protocol: 'tls', tlsVersion: tlsVersionToString(tlsMajor, tlsMinor) || undefined }; // If it's a handshake, try to extract more info if (recordType === TlsRecordType.HANDSHAKE && buffer.length >= 6) { const handshakeType = buffer[5]; // For ClientHello, extract SNI and other info if (handshakeType === TlsHandshakeType.CLIENT_HELLO) { // Check if we have the complete handshake const totalRecordLength = recordLength + 5; // Including TLS header if (buffer.length >= totalRecordLength) { // Extract SNI using existing logic const sni = SniExtraction.extractSNI(buffer); if (sni) { connectionInfo.domain = sni; connectionInfo.sni = sni; } // Parse ClientHello for additional info const parseResult = ClientHelloParser.parseClientHello(buffer); if (parseResult.isValid) { // Extract ALPN if present const alpnExtension = parseResult.extensions.find(ext => ext.type === TlsExtensionType.APPLICATION_LAYER_PROTOCOL_NEGOTIATION); if (alpnExtension) { connectionInfo.alpn = this.parseAlpnExtension(alpnExtension.data); } // Store cipher suites if needed if (parseResult.cipherSuites && options?.extractFullHeaders) { connectionInfo.cipherSuites = this.parseCipherSuites(parseResult.cipherSuites); } } // Return complete result return { protocol: 'tls', connectionInfo, remainingBuffer: buffer.length > totalRecordLength ? buffer.subarray(totalRecordLength) : undefined, isComplete: true }; } else { // Incomplete handshake return { protocol: 'tls', connectionInfo, isComplete: false, bytesNeeded: totalRecordLength }; } } } // For other TLS record types, just return basic info return { protocol: 'tls', connectionInfo, isComplete: true, remainingBuffer: buffer.length > recordLength + 5 ? buffer.subarray(recordLength + 5) : undefined }; } /** * Check if buffer can be handled by this detector */ canHandle(buffer) { return buffer.length >= TlsDetector.MIN_TLS_HEADER_SIZE && this.isTlsRecord(buffer); } /** * Get minimum bytes needed for detection */ getMinimumBytes() { return TlsDetector.MIN_TLS_HEADER_SIZE; } /** * Check if buffer contains a valid TLS record */ isTlsRecord(buffer) { const recordType = buffer[0]; // Check for valid record type const validTypes = [ TlsRecordType.CHANGE_CIPHER_SPEC, TlsRecordType.ALERT, TlsRecordType.HANDSHAKE, TlsRecordType.APPLICATION_DATA, TlsRecordType.HEARTBEAT ]; if (!validTypes.includes(recordType)) { return false; } // Check TLS version bytes (should be 0x03 0x0X) if (buffer[1] !== 0x03) { return false; } // Check record length is reasonable const recordLength = readUInt16BE(buffer, 3); if (recordLength > 16384) { // Max TLS record size return false; } return true; } /** * Parse ALPN extension data */ parseAlpnExtension(data) { const protocols = []; if (data.length < 2) { return protocols; } const listLength = readUInt16BE(data, 0); let offset = 2; while (offset < Math.min(2 + listLength, data.length)) { const protoLength = data[offset]; offset++; if (offset + protoLength <= data.length) { const protocol = data.subarray(offset, offset + protoLength).toString('ascii'); protocols.push(protocol); offset += protoLength; } else { break; } } return protocols; } /** * Parse cipher suites */ parseCipherSuites(cipherData) { const suites = []; for (let i = 0; i < cipherData.length - 1; i += 2) { const suite = readUInt16BE(cipherData, i); suites.push(suite); } return suites; } /** * Detect with context for fragmented data */ detectWithContext(buffer, _context, options) { // This method is deprecated - TLS detection should use the fragment manager // from the parent detector system, not maintain its own fragments return this.detect(buffer, options); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGxzLWRldGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvZGV0ZWN0aW9uL2RldGVjdG9ycy90bHMtZGV0ZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFLSCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFOUQsd0JBQXdCO0FBQ3hCLE9BQU8sRUFBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUVqRyx5REFBeUQ7QUFDekQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQzFFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdEQUFnRCxDQUFDO0FBRW5GOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFDdEI7O09BRUc7YUFDcUIsd0JBQW1CLEdBQUcsQ0FBQyxDQUFDO0lBR2hEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLE1BQWMsRUFBRSxPQUEyQjtRQUNoRCwrQkFBK0I7UUFDL0IsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLFdBQVcsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ3BELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELGdDQUFnQztRQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQzlCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELHlCQUF5QjtRQUN6QixNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDN0IsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNCLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMzQixNQUFNLFlBQVks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