/** * Quick Protocol Detector * * Lightweight protocol identification based on minimal bytes * No parsing, just identification */ import type { IProtocolDetector, IProtocolDetectionResult } from '../../protocols/common/types.js'; import { TlsRecordType } from '../../protocols/tls/index.js'; import { HttpParser } from '../../protocols/http/index.js'; /** * Quick protocol detector for fast identification */ export class QuickProtocolDetector implements IProtocolDetector { /** * Check if this detector can handle the data */ canHandle(data: Buffer): boolean { return data.length >= 1; } /** * Perform quick detection based on first few bytes */ quickDetect(data: Buffer): IProtocolDetectionResult { if (data.length === 0) { return { protocol: 'unknown', confidence: 0, requiresMoreData: true }; } // Check for TLS const tlsResult = this.checkTls(data); if (tlsResult.confidence > 80) { return tlsResult; } // Check for HTTP const httpResult = this.checkHttp(data); if (httpResult.confidence > 80) { return httpResult; } // Need more data or unknown return { protocol: 'unknown', confidence: 0, requiresMoreData: data.length < 20 }; } /** * Check if data looks like TLS */ private checkTls(data: Buffer): IProtocolDetectionResult { if (data.length < 3) { return { protocol: 'tls', confidence: 0, requiresMoreData: true }; } const firstByte = data[0]; const secondByte = data[1]; // Check for valid TLS record type const validRecordTypes = [ TlsRecordType.CHANGE_CIPHER_SPEC, TlsRecordType.ALERT, TlsRecordType.HANDSHAKE, TlsRecordType.APPLICATION_DATA, TlsRecordType.HEARTBEAT ]; if (!validRecordTypes.includes(firstByte)) { return { protocol: 'tls', confidence: 0 }; } // Check TLS version byte (0x03 for all TLS/SSL versions) if (secondByte !== 0x03) { return { protocol: 'tls', confidence: 0 }; } // High confidence it's TLS return { protocol: 'tls', confidence: 95, metadata: { recordType: firstByte } }; } /** * Check if data looks like HTTP */ private checkHttp(data: Buffer): IProtocolDetectionResult { if (data.length < 3) { return { protocol: 'http', confidence: 0, requiresMoreData: true }; } // Quick check for HTTP methods const start = data.subarray(0, Math.min(10, data.length)).toString('ascii'); // Check common HTTP methods const httpMethods = ['GET ', 'POST ', 'PUT ', 'DELETE ', 'HEAD ', 'OPTIONS', 'PATCH ', 'CONNECT', 'TRACE ']; for (const method of httpMethods) { if (start.startsWith(method)) { return { protocol: 'http', confidence: 95, metadata: { method: method.trim() } }; } } // Check if it might be HTTP but need more data if (HttpParser.isPrintableAscii(data, Math.min(20, data.length))) { // Could be HTTP, but not sure return { protocol: 'http', confidence: 30, requiresMoreData: data.length < 20 }; } return { protocol: 'http', confidence: 0 }; } }