update
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
// TLS detector doesn't need plugins imports
|
||||
import type { IProtocolDetector } from '../models/interfaces.js';
|
||||
import type { IDetectionResult, IDetectionOptions, IConnectionInfo } from '../models/detection-types.js';
|
||||
import { readUInt16BE, BufferAccumulator } from '../utils/buffer-utils.js';
|
||||
import { readUInt16BE } from '../utils/buffer-utils.js';
|
||||
import { tlsVersionToString } from '../utils/parser-utils.js';
|
||||
|
||||
// Import from protocols
|
||||
@@ -24,17 +24,6 @@ export class TlsDetector implements IProtocolDetector {
|
||||
*/
|
||||
private static readonly MIN_TLS_HEADER_SIZE = 5;
|
||||
|
||||
/**
|
||||
* Fragment tracking for incomplete handshakes
|
||||
*/
|
||||
private static fragmentedBuffers = new Map<string, BufferAccumulator>();
|
||||
|
||||
/**
|
||||
* Create connection ID from context
|
||||
*/
|
||||
private createConnectionId(context: { sourceIp?: string; sourcePort?: number; destIp?: string; destPort?: number }): string {
|
||||
return `${context.sourceIp || 'unknown'}:${context.sourcePort || 0}->${context.destIp || 'unknown'}:${context.destPort || 0}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect TLS protocol from buffer
|
||||
@@ -224,29 +213,11 @@ export class TlsDetector implements IProtocolDetector {
|
||||
*/
|
||||
detectWithContext(
|
||||
buffer: Buffer,
|
||||
context: { sourceIp?: string; sourcePort?: number; destIp?: string; destPort?: number },
|
||||
_context: { sourceIp?: string; sourcePort?: number; destIp?: string; destPort?: number },
|
||||
options?: IDetectionOptions
|
||||
): IDetectionResult | null {
|
||||
const connectionId = this.createConnectionId(context);
|
||||
|
||||
// Get or create buffer accumulator for this connection
|
||||
let accumulator = TlsDetector.fragmentedBuffers.get(connectionId);
|
||||
if (!accumulator) {
|
||||
accumulator = new BufferAccumulator();
|
||||
TlsDetector.fragmentedBuffers.set(connectionId, accumulator);
|
||||
}
|
||||
|
||||
// Add new data
|
||||
accumulator.append(buffer);
|
||||
|
||||
// Try detection on accumulated data
|
||||
const result = this.detect(accumulator.getBuffer(), options);
|
||||
|
||||
// If detection is complete or we have too much data, clean up
|
||||
if (result?.isComplete || accumulator.length() > 65536) {
|
||||
TlsDetector.fragmentedBuffers.delete(connectionId);
|
||||
}
|
||||
|
||||
return result;
|
||||
// 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);
|
||||
}
|
||||
}
|
@@ -120,10 +120,28 @@ export class ProtocolDetector {
|
||||
};
|
||||
}
|
||||
|
||||
const connectionId = DetectionFragmentManager.createConnectionId(context);
|
||||
|
||||
// First peek to determine protocol type
|
||||
if (this.tlsDetector.canHandle(buffer)) {
|
||||
const result = this.tlsDetector.detectWithContext(buffer, context, options);
|
||||
// Handle TLS with fragment accumulation
|
||||
const handler = this.fragmentManager.getHandler('tls');
|
||||
const fragmentResult = handler.addFragment(connectionId, buffer);
|
||||
|
||||
if (fragmentResult.error) {
|
||||
handler.complete(connectionId);
|
||||
return {
|
||||
protocol: 'unknown',
|
||||
connectionInfo: { protocol: 'unknown' },
|
||||
isComplete: true
|
||||
};
|
||||
}
|
||||
|
||||
const result = this.tlsDetector.detect(fragmentResult.buffer!, options);
|
||||
if (result) {
|
||||
if (result.isComplete) {
|
||||
handler.complete(connectionId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -173,13 +191,25 @@ export class ProtocolDetector {
|
||||
/**
|
||||
* Clean up old connection tracking entries
|
||||
*
|
||||
* @param maxAge Maximum age in milliseconds (default: 30 seconds)
|
||||
* @param _maxAge Maximum age in milliseconds (default: 30 seconds)
|
||||
*/
|
||||
static cleanupConnections(maxAge: number = 30000): void {
|
||||
static cleanupConnections(_maxAge: number = 30000): void {
|
||||
// Cleanup is now handled internally by the fragment manager
|
||||
this.getInstance().fragmentManager.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up fragments for a specific connection
|
||||
*/
|
||||
static cleanupConnection(context: IConnectionContext): void {
|
||||
const instance = this.getInstance();
|
||||
const connectionId = DetectionFragmentManager.createConnectionId(context);
|
||||
|
||||
// Clean up both TLS and HTTP fragments for this connection
|
||||
instance.fragmentManager.getHandler('tls').complete(connectionId);
|
||||
instance.fragmentManager.getHandler('http').complete(connectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract domain from connection info
|
||||
*/
|
||||
|
@@ -5,6 +5,7 @@ import { connectionLogDeduplicator } from '../../core/utils/log-deduplicator.js'
|
||||
import { LifecycleComponent } from '../../core/utils/lifecycle-component.js';
|
||||
import { cleanupSocket } from '../../core/utils/socket-utils.js';
|
||||
import { WrappedSocket } from '../../core/models/wrapped-socket.js';
|
||||
import { ProtocolDetector } from '../../detection/index.js';
|
||||
import type { SmartProxy } from './smart-proxy.js';
|
||||
|
||||
/**
|
||||
@@ -323,6 +324,18 @@ export class ConnectionManager extends LifecycleComponent {
|
||||
this.smartProxy.metricsCollector.removeConnection(record.id);
|
||||
}
|
||||
|
||||
// Clean up protocol detection fragments
|
||||
const context = ProtocolDetector.createConnectionContext({
|
||||
sourceIp: record.remoteIP,
|
||||
sourcePort: record.incoming?.remotePort || 0,
|
||||
destIp: record.incoming?.localAddress || '',
|
||||
destPort: record.localPort,
|
||||
socketId: record.id
|
||||
});
|
||||
|
||||
// Clean up any pending detection fragments for this connection
|
||||
ProtocolDetector.cleanupConnection(context);
|
||||
|
||||
if (record.cleanupTimer) {
|
||||
clearTimeout(record.cleanupTimer);
|
||||
record.cleanupTimer = undefined;
|
||||
|
@@ -303,18 +303,18 @@ export class RouteConnectionHandler {
|
||||
|
||||
// Handler for processing initial data (after potential PROXY protocol)
|
||||
const processInitialData = async (chunk: Buffer) => {
|
||||
// Use ProtocolDetector to identify protocol
|
||||
const connectionId = ProtocolDetector.createConnectionId({
|
||||
// Create connection context for protocol detection
|
||||
const context = ProtocolDetector.createConnectionContext({
|
||||
sourceIp: record.remoteIP,
|
||||
sourcePort: socket.remotePort,
|
||||
destIp: socket.localAddress,
|
||||
destPort: socket.localPort,
|
||||
sourcePort: socket.remotePort || 0,
|
||||
destIp: socket.localAddress || '',
|
||||
destPort: socket.localPort || 0,
|
||||
socketId: record.id
|
||||
});
|
||||
|
||||
const detectionResult = await ProtocolDetector.detectWithConnectionTracking(
|
||||
const detectionResult = await ProtocolDetector.detectWithContext(
|
||||
chunk,
|
||||
connectionId,
|
||||
context,
|
||||
{ extractFullHeaders: false } // Only extract essential info for routing
|
||||
);
|
||||
|
||||
|
Reference in New Issue
Block a user