2025-07-21 19:40:01 +00:00
|
|
|
/**
|
2025-07-22 00:19:59 +00:00
|
|
|
* Protocol Detector
|
|
|
|
*
|
|
|
|
* Simplified protocol detection using the new architecture
|
2025-07-21 19:40:01 +00:00
|
|
|
*/
|
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
import type { IDetectionResult, IDetectionOptions } from './models/detection-types.js';
|
|
|
|
import type { IConnectionContext } from '../protocols/common/types.js';
|
2025-07-21 19:40:01 +00:00
|
|
|
import { TlsDetector } from './detectors/tls-detector.js';
|
|
|
|
import { HttpDetector } from './detectors/http-detector.js';
|
2025-07-22 00:19:59 +00:00
|
|
|
import { DetectionFragmentManager } from './utils/fragment-manager.js';
|
2025-07-21 19:40:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Main protocol detector class
|
|
|
|
*/
|
|
|
|
export class ProtocolDetector {
|
2025-07-22 00:19:59 +00:00
|
|
|
private static instance: ProtocolDetector;
|
|
|
|
private fragmentManager: DetectionFragmentManager;
|
|
|
|
private tlsDetector: TlsDetector;
|
|
|
|
private httpDetector: HttpDetector;
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
this.fragmentManager = new DetectionFragmentManager();
|
|
|
|
this.tlsDetector = new TlsDetector();
|
|
|
|
this.httpDetector = new HttpDetector(this.fragmentManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static getInstance(): ProtocolDetector {
|
|
|
|
if (!this.instance) {
|
|
|
|
this.instance = new ProtocolDetector();
|
|
|
|
}
|
|
|
|
return this.instance;
|
|
|
|
}
|
2025-07-21 19:40:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Detect protocol from buffer data
|
|
|
|
*/
|
2025-07-22 00:19:59 +00:00
|
|
|
static async detect(buffer: Buffer, options?: IDetectionOptions): Promise<IDetectionResult> {
|
|
|
|
return this.getInstance().detectInstance(buffer, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
private async detectInstance(buffer: Buffer, options?: IDetectionOptions): Promise<IDetectionResult> {
|
2025-07-21 19:40:01 +00:00
|
|
|
// Quick sanity check
|
|
|
|
if (!buffer || buffer.length === 0) {
|
|
|
|
return {
|
|
|
|
protocol: 'unknown',
|
|
|
|
connectionInfo: { protocol: 'unknown' },
|
|
|
|
isComplete: true
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try TLS detection first (more specific)
|
2025-07-22 00:19:59 +00:00
|
|
|
if (this.tlsDetector.canHandle(buffer)) {
|
|
|
|
const tlsResult = this.tlsDetector.detect(buffer, options);
|
2025-07-21 19:40:01 +00:00
|
|
|
if (tlsResult) {
|
|
|
|
return tlsResult;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try HTTP detection
|
2025-07-22 00:19:59 +00:00
|
|
|
if (this.httpDetector.canHandle(buffer)) {
|
|
|
|
const httpResult = this.httpDetector.detect(buffer, options);
|
2025-07-21 19:40:01 +00:00
|
|
|
if (httpResult) {
|
|
|
|
return httpResult;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Neither TLS nor HTTP
|
|
|
|
return {
|
|
|
|
protocol: 'unknown',
|
|
|
|
connectionInfo: { protocol: 'unknown' },
|
|
|
|
isComplete: true
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Detect protocol with connection tracking for fragmented data
|
2025-07-22 00:19:59 +00:00
|
|
|
* @deprecated Use detectWithContext instead
|
2025-07-21 19:40:01 +00:00
|
|
|
*/
|
|
|
|
static async detectWithConnectionTracking(
|
|
|
|
buffer: Buffer,
|
|
|
|
connectionId: string,
|
|
|
|
options?: IDetectionOptions
|
|
|
|
): Promise<IDetectionResult> {
|
2025-07-22 00:19:59 +00:00
|
|
|
// Convert connection ID to context
|
|
|
|
const context: IConnectionContext = {
|
|
|
|
id: connectionId,
|
|
|
|
sourceIp: 'unknown',
|
|
|
|
sourcePort: 0,
|
|
|
|
destIp: 'unknown',
|
|
|
|
destPort: 0,
|
|
|
|
timestamp: Date.now()
|
|
|
|
};
|
2025-07-21 19:40:01 +00:00
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
return this.getInstance().detectWithContextInstance(buffer, context, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Detect protocol with connection context for fragmented data
|
|
|
|
*/
|
|
|
|
static async detectWithContext(
|
|
|
|
buffer: Buffer,
|
|
|
|
context: IConnectionContext,
|
|
|
|
options?: IDetectionOptions
|
|
|
|
): Promise<IDetectionResult> {
|
|
|
|
return this.getInstance().detectWithContextInstance(buffer, context, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
private async detectWithContextInstance(
|
|
|
|
buffer: Buffer,
|
|
|
|
context: IConnectionContext,
|
|
|
|
options?: IDetectionOptions
|
|
|
|
): Promise<IDetectionResult> {
|
|
|
|
// Quick sanity check
|
|
|
|
if (!buffer || buffer.length === 0) {
|
|
|
|
return {
|
2025-07-21 19:40:01 +00:00
|
|
|
protocol: 'unknown',
|
|
|
|
connectionInfo: { protocol: 'unknown' },
|
|
|
|
isComplete: true
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
// First peek to determine protocol type
|
|
|
|
if (this.tlsDetector.canHandle(buffer)) {
|
|
|
|
const result = this.tlsDetector.detectWithContext(buffer, context, options);
|
|
|
|
if (result) {
|
|
|
|
return result;
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|
2025-07-22 00:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this.httpDetector.canHandle(buffer)) {
|
|
|
|
const result = this.httpDetector.detectWithContext(buffer, context, options);
|
|
|
|
if (result) {
|
|
|
|
return result;
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
// Can't determine protocol
|
2025-07-21 19:40:01 +00:00
|
|
|
return {
|
|
|
|
protocol: 'unknown',
|
|
|
|
connectionInfo: { protocol: 'unknown' },
|
|
|
|
isComplete: false,
|
2025-07-22 00:19:59 +00:00
|
|
|
bytesNeeded: Math.max(
|
|
|
|
this.tlsDetector.getMinimumBytes(),
|
|
|
|
this.httpDetector.getMinimumBytes()
|
|
|
|
)
|
2025-07-21 19:40:01 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
/**
|
|
|
|
* Clean up resources
|
|
|
|
*/
|
|
|
|
static cleanup(): void {
|
|
|
|
this.getInstance().cleanupInstance();
|
|
|
|
}
|
|
|
|
|
|
|
|
private cleanupInstance(): void {
|
|
|
|
this.fragmentManager.cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destroy detector instance
|
|
|
|
*/
|
|
|
|
static destroy(): void {
|
|
|
|
this.getInstance().destroyInstance();
|
|
|
|
this.instance = null as any;
|
|
|
|
}
|
|
|
|
|
|
|
|
private destroyInstance(): void {
|
|
|
|
this.fragmentManager.destroy();
|
|
|
|
}
|
|
|
|
|
2025-07-21 19:40:01 +00:00
|
|
|
/**
|
|
|
|
* Clean up old connection tracking entries
|
|
|
|
*
|
|
|
|
* @param maxAge Maximum age in milliseconds (default: 30 seconds)
|
|
|
|
*/
|
|
|
|
static cleanupConnections(maxAge: number = 30000): void {
|
2025-07-22 00:19:59 +00:00
|
|
|
// Cleanup is now handled internally by the fragment manager
|
|
|
|
this.getInstance().fragmentManager.cleanup();
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract domain from connection info
|
|
|
|
*/
|
2025-07-22 00:19:59 +00:00
|
|
|
static extractDomain(connectionInfo: any): string | undefined {
|
|
|
|
return connectionInfo.domain || connectionInfo.sni || connectionInfo.host;
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a connection ID from connection parameters
|
2025-07-22 00:19:59 +00:00
|
|
|
* @deprecated Use createConnectionContext instead
|
2025-07-21 19:40:01 +00:00
|
|
|
*/
|
|
|
|
static createConnectionId(params: {
|
|
|
|
sourceIp?: string;
|
|
|
|
sourcePort?: number;
|
|
|
|
destIp?: string;
|
|
|
|
destPort?: number;
|
|
|
|
socketId?: string;
|
|
|
|
}): string {
|
|
|
|
// If socketId is provided, use it
|
|
|
|
if (params.socketId) {
|
|
|
|
return params.socketId;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise create from connection tuple
|
|
|
|
const { sourceIp = 'unknown', sourcePort = 0, destIp = 'unknown', destPort = 0 } = params;
|
|
|
|
return `${sourceIp}:${sourcePort}-${destIp}:${destPort}`;
|
|
|
|
}
|
2025-07-22 00:19:59 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a connection context from parameters
|
|
|
|
*/
|
|
|
|
static createConnectionContext(params: {
|
|
|
|
sourceIp?: string;
|
|
|
|
sourcePort?: number;
|
|
|
|
destIp?: string;
|
|
|
|
destPort?: number;
|
|
|
|
socketId?: string;
|
|
|
|
}): IConnectionContext {
|
|
|
|
return {
|
|
|
|
id: params.socketId,
|
|
|
|
sourceIp: params.sourceIp || 'unknown',
|
|
|
|
sourcePort: params.sourcePort || 0,
|
|
|
|
destIp: params.destIp || 'unknown',
|
|
|
|
destPort: params.destPort || 0,
|
|
|
|
timestamp: Date.now()
|
|
|
|
};
|
|
|
|
}
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|