@push.rocks/smartproxy 21.1.0 → 21.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 2025-07-22 - 21.1.1 - fix(detection)
4
+ Fix SNI detection in TLS detector
5
+
6
+ - Restored proper TLS detector implementation with ClientHello parsing
7
+ - Fixed imports to use new protocols module locations
8
+ - Added missing detectWithContext method for fragmented detection
9
+ - Fixed method names to match BufferAccumulator interface
10
+ - Removed unused import readUInt24BE
11
+
3
12
  ## 2025-07-21 - 21.1.0 - feat(protocols)
4
13
  Refactor protocol utilities into centralized protocols module
5
14
 
@@ -1,19 +1,28 @@
1
1
  /**
2
- * TLS Protocol Detector
3
- *
4
- * Simplified TLS detection using the new architecture
2
+ * TLS protocol detector
5
3
  */
6
4
  import type { IProtocolDetector } from '../models/interfaces.js';
7
5
  import type { IDetectionResult, IDetectionOptions } from '../models/detection-types.js';
8
- import type { IConnectionContext } from '../../protocols/common/types.js';
9
- import { DetectionFragmentManager } from '../utils/fragment-manager.js';
10
6
  /**
11
- * Simplified TLS detector
7
+ * TLS detector implementation
12
8
  */
13
9
  export declare class TlsDetector implements IProtocolDetector {
14
- private quickDetector;
15
- private fragmentManager;
16
- constructor(fragmentManager?: DetectionFragmentManager);
10
+ /**
11
+ * Minimum bytes needed to identify TLS (record header)
12
+ */
13
+ private static readonly MIN_TLS_HEADER_SIZE;
14
+ /**
15
+ * Fragment tracking for incomplete handshakes
16
+ */
17
+ private static fragmentedBuffers;
18
+ /**
19
+ * Create connection ID from context
20
+ */
21
+ private createConnectionId;
22
+ /**
23
+ * Detect TLS protocol from buffer
24
+ */
25
+ detect(buffer: Buffer, options?: IDetectionOptions): IDetectionResult | null;
17
26
  /**
18
27
  * Check if buffer can be handled by this detector
19
28
  */
@@ -23,11 +32,24 @@ export declare class TlsDetector implements IProtocolDetector {
23
32
  */
24
33
  getMinimumBytes(): number;
25
34
  /**
26
- * Detect TLS protocol from buffer
35
+ * Check if buffer contains a valid TLS record
27
36
  */
28
- detect(buffer: Buffer, options?: IDetectionOptions): IDetectionResult | null;
37
+ private isTlsRecord;
38
+ /**
39
+ * Parse ALPN extension data
40
+ */
41
+ private parseAlpnExtension;
42
+ /**
43
+ * Parse cipher suites
44
+ */
45
+ private parseCipherSuites;
29
46
  /**
30
- * Handle fragmented detection
47
+ * Detect with context for fragmented data
31
48
  */
32
- detectWithContext(buffer: Buffer, context: IConnectionContext, options?: IDetectionOptions): IDetectionResult | null;
49
+ detectWithContext(buffer: Buffer, context: {
50
+ sourceIp?: string;
51
+ sourcePort?: number;
52
+ destIp?: string;
53
+ destPort?: number;
54
+ }, options?: IDetectionOptions): IDetectionResult | null;
33
55
  }
@@ -1,106 +1,206 @@
1
1
  /**
2
- * TLS Protocol Detector
3
- *
4
- * Simplified TLS detection using the new architecture
2
+ * TLS protocol detector
5
3
  */
6
- import { QuickProtocolDetector } from './quick-detector.js';
7
- import { RoutingExtractor } from './routing-extractor.js';
8
- import { DetectionFragmentManager } from '../utils/fragment-manager.js';
4
+ import { readUInt16BE, readUInt24BE, BufferAccumulator } from '../utils/buffer-utils.js';
5
+ import { tlsVersionToString } from '../utils/parser-utils.js';
6
+ // Import from protocols
7
+ import { TlsRecordType, TlsHandshakeType, TlsExtensionType } from '../../protocols/tls/index.js';
8
+ // Import TLS utilities for SNI extraction from protocols
9
+ import { SniExtraction } from '../../protocols/tls/sni/sni-extraction.js';
10
+ import { ClientHelloParser } from '../../protocols/tls/sni/client-hello-parser.js';
9
11
  /**
10
- * Simplified TLS detector
12
+ * TLS detector implementation
11
13
  */
12
14
  export class TlsDetector {
13
- constructor(fragmentManager) {
14
- this.quickDetector = new QuickProtocolDetector();
15
- this.fragmentManager = fragmentManager || new DetectionFragmentManager();
15
+ /**
16
+ * Minimum bytes needed to identify TLS (record header)
17
+ */
18
+ static { this.MIN_TLS_HEADER_SIZE = 5; }
19
+ /**
20
+ * Fragment tracking for incomplete handshakes
21
+ */
22
+ static { this.fragmentedBuffers = new Map(); }
23
+ /**
24
+ * Create connection ID from context
25
+ */
26
+ createConnectionId(context) {
27
+ return `${context.sourceIp || 'unknown'}:${context.sourcePort || 0}->${context.destIp || 'unknown'}:${context.destPort || 0}`;
28
+ }
29
+ /**
30
+ * Detect TLS protocol from buffer
31
+ */
32
+ detect(buffer, options) {
33
+ // Check if buffer is too small
34
+ if (buffer.length < TlsDetector.MIN_TLS_HEADER_SIZE) {
35
+ return null;
36
+ }
37
+ // Check if this is a TLS record
38
+ if (!this.isTlsRecord(buffer)) {
39
+ return null;
40
+ }
41
+ // Extract basic TLS info
42
+ const recordType = buffer[0];
43
+ const tlsMajor = buffer[1];
44
+ const tlsMinor = buffer[2];
45
+ const recordLength = readUInt16BE(buffer, 3);
46
+ // Initialize connection info
47
+ const connectionInfo = {
48
+ protocol: 'tls',
49
+ tlsVersion: tlsVersionToString(tlsMajor, tlsMinor) || undefined
50
+ };
51
+ // If it's a handshake, try to extract more info
52
+ if (recordType === TlsRecordType.HANDSHAKE && buffer.length >= 6) {
53
+ const handshakeType = buffer[5];
54
+ // For ClientHello, extract SNI and other info
55
+ if (handshakeType === TlsHandshakeType.CLIENT_HELLO) {
56
+ // Check if we have the complete handshake
57
+ const totalRecordLength = recordLength + 5; // Including TLS header
58
+ if (buffer.length >= totalRecordLength) {
59
+ // Extract SNI using existing logic
60
+ const sni = SniExtraction.extractSNI(buffer);
61
+ if (sni) {
62
+ connectionInfo.domain = sni;
63
+ connectionInfo.sni = sni;
64
+ }
65
+ // Parse ClientHello for additional info
66
+ const parseResult = ClientHelloParser.parseClientHello(buffer);
67
+ if (parseResult.isValid) {
68
+ // Extract ALPN if present
69
+ const alpnExtension = parseResult.extensions.find(ext => ext.type === TlsExtensionType.APPLICATION_LAYER_PROTOCOL_NEGOTIATION);
70
+ if (alpnExtension) {
71
+ connectionInfo.alpn = this.parseAlpnExtension(alpnExtension.data);
72
+ }
73
+ // Store cipher suites if needed
74
+ if (parseResult.cipherSuites && options?.extractFullHeaders) {
75
+ connectionInfo.cipherSuites = this.parseCipherSuites(parseResult.cipherSuites);
76
+ }
77
+ }
78
+ // Return complete result
79
+ return {
80
+ protocol: 'tls',
81
+ connectionInfo,
82
+ remainingBuffer: buffer.length > totalRecordLength
83
+ ? buffer.subarray(totalRecordLength)
84
+ : undefined,
85
+ isComplete: true
86
+ };
87
+ }
88
+ else {
89
+ // Incomplete handshake
90
+ return {
91
+ protocol: 'tls',
92
+ connectionInfo,
93
+ isComplete: false,
94
+ bytesNeeded: totalRecordLength
95
+ };
96
+ }
97
+ }
98
+ }
99
+ // For other TLS record types, just return basic info
100
+ return {
101
+ protocol: 'tls',
102
+ connectionInfo,
103
+ isComplete: true,
104
+ remainingBuffer: buffer.length > recordLength + 5
105
+ ? buffer.subarray(recordLength + 5)
106
+ : undefined
107
+ };
16
108
  }
17
109
  /**
18
110
  * Check if buffer can be handled by this detector
19
111
  */
20
112
  canHandle(buffer) {
21
- const result = this.quickDetector.quickDetect(buffer);
22
- return result.protocol === 'tls' && result.confidence > 50;
113
+ return buffer.length >= TlsDetector.MIN_TLS_HEADER_SIZE &&
114
+ this.isTlsRecord(buffer);
23
115
  }
24
116
  /**
25
117
  * Get minimum bytes needed for detection
26
118
  */
27
119
  getMinimumBytes() {
28
- return 5; // TLS record header
120
+ return TlsDetector.MIN_TLS_HEADER_SIZE;
29
121
  }
30
122
  /**
31
- * Detect TLS protocol from buffer
123
+ * Check if buffer contains a valid TLS record
32
124
  */
33
- detect(buffer, options) {
34
- // Quick detection first
35
- const quickResult = this.quickDetector.quickDetect(buffer);
36
- if (quickResult.protocol !== 'tls' || quickResult.confidence < 50) {
37
- return null;
125
+ isTlsRecord(buffer) {
126
+ const recordType = buffer[0];
127
+ // Check for valid record type
128
+ const validTypes = [
129
+ TlsRecordType.CHANGE_CIPHER_SPEC,
130
+ TlsRecordType.ALERT,
131
+ TlsRecordType.HANDSHAKE,
132
+ TlsRecordType.APPLICATION_DATA,
133
+ TlsRecordType.HEARTBEAT
134
+ ];
135
+ if (!validTypes.includes(recordType)) {
136
+ return false;
38
137
  }
39
- // Extract TLS version for compatibility
40
- let tlsVersion;
41
- if (buffer.length >= 3) {
42
- const versionByte = buffer[2];
43
- switch (versionByte) {
44
- case 0x00:
45
- tlsVersion = 'SSLv3';
46
- break;
47
- case 0x01:
48
- tlsVersion = 'TLSv1.0';
49
- break;
50
- case 0x02:
51
- tlsVersion = 'TLSv1.1';
52
- break;
53
- case 0x03:
54
- tlsVersion = 'TLSv1.2';
55
- break;
56
- case 0x04:
57
- tlsVersion = 'TLSv1.3';
58
- break;
138
+ // Check TLS version bytes (should be 0x03 0x0X)
139
+ if (buffer[1] !== 0x03) {
140
+ return false;
141
+ }
142
+ // Check record length is reasonable
143
+ const recordLength = readUInt16BE(buffer, 3);
144
+ if (recordLength > 16384) { // Max TLS record size
145
+ return false;
146
+ }
147
+ return true;
148
+ }
149
+ /**
150
+ * Parse ALPN extension data
151
+ */
152
+ parseAlpnExtension(data) {
153
+ const protocols = [];
154
+ if (data.length < 2) {
155
+ return protocols;
156
+ }
157
+ const listLength = readUInt16BE(data, 0);
158
+ let offset = 2;
159
+ while (offset < Math.min(2 + listLength, data.length)) {
160
+ const protoLength = data[offset];
161
+ offset++;
162
+ if (offset + protoLength <= data.length) {
163
+ const protocol = data.subarray(offset, offset + protoLength).toString('ascii');
164
+ protocols.push(protocol);
165
+ offset += protoLength;
166
+ }
167
+ else {
168
+ break;
59
169
  }
60
170
  }
61
- // If we don't need domain extraction, we can return early
62
- if (quickResult.confidence >= 95 && !options?.extractFullHeaders) {
63
- return {
64
- protocol: 'tls',
65
- connectionInfo: {
66
- protocol: 'tls',
67
- tlsVersion: tlsVersion
68
- },
69
- isComplete: true
70
- };
171
+ return protocols;
172
+ }
173
+ /**
174
+ * Parse cipher suites
175
+ */
176
+ parseCipherSuites(cipherData) {
177
+ const suites = [];
178
+ for (let i = 0; i < cipherData.length - 1; i += 2) {
179
+ const suite = readUInt16BE(cipherData, i);
180
+ suites.push(suite);
71
181
  }
72
- // Extract routing information if needed
73
- const routing = RoutingExtractor.extract(buffer, 'tls');
74
- return {
75
- protocol: 'tls',
76
- connectionInfo: {
77
- protocol: 'tls',
78
- domain: routing?.domain,
79
- sni: routing?.domain,
80
- tlsVersion: tlsVersion
81
- },
82
- isComplete: !quickResult.requiresMoreData,
83
- bytesNeeded: quickResult.requiresMoreData ? buffer.length + 100 : undefined
84
- };
182
+ return suites;
85
183
  }
86
184
  /**
87
- * Handle fragmented detection
185
+ * Detect with context for fragmented data
88
186
  */
89
187
  detectWithContext(buffer, context, options) {
90
- const handler = this.fragmentManager.getHandler('tls');
91
- const connectionId = DetectionFragmentManager.createConnectionId(context);
92
- // Add fragment
93
- const result = handler.addFragment(connectionId, buffer);
94
- if (result.error) {
95
- handler.complete(connectionId);
96
- return null;
188
+ const connectionId = this.createConnectionId(context);
189
+ // Get or create buffer accumulator for this connection
190
+ let accumulator = TlsDetector.fragmentedBuffers.get(connectionId);
191
+ if (!accumulator) {
192
+ accumulator = new BufferAccumulator();
193
+ TlsDetector.fragmentedBuffers.set(connectionId, accumulator);
97
194
  }
98
- // Try detection on accumulated buffer
99
- const detectResult = this.detect(result.buffer, options);
100
- if (detectResult && detectResult.isComplete) {
101
- handler.complete(connectionId);
195
+ // Add new data
196
+ accumulator.append(buffer);
197
+ // Try detection on accumulated data
198
+ const result = this.detect(accumulator.getBuffer(), options);
199
+ // If detection is complete or we have too much data, clean up
200
+ if (result?.isComplete || accumulator.length() > 65536) {
201
+ TlsDetector.fragmentedBuffers.delete(connectionId);
102
202
  }
103
- return detectResult;
203
+ return result;
104
204
  }
105
205
  }
106
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGxzLWRldGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvZGV0ZWN0aW9uL2RldGVjdG9ycy90bHMtZGV0ZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUtILE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzVELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzFELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRXhFOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFJdEIsWUFBWSxlQUEwQztRQUg5QyxrQkFBYSxHQUFHLElBQUkscUJBQXFCLEVBQUUsQ0FBQztRQUlsRCxJQUFJLENBQUMsZUFBZSxHQUFHLGVBQWUsSUFBSSxJQUFJLHdCQUF3QixFQUFFLENBQUM7SUFDM0UsQ0FBQztJQUVEOztPQUVHO0lBQ0gsU0FBUyxDQUFDLE1BQWM7UUFDdEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEQsT0FBTyxNQUFNLENBQUMsUUFBUSxLQUFLLEtBQUssSUFBSSxNQUFNLENBQUMsVUFBVSxHQUFHLEVBQUUsQ0FBQztJQUM3RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxlQUFlO1FBQ2IsT0FBTyxDQUFDLENBQUMsQ0FBQyxvQkFBb0I7SUFDaEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLE1BQWMsRUFBRSxPQUEyQjtRQUNoRCx3QkFBd0I7UUFDeEIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFM0QsSUFBSSxXQUFXLENBQUMsUUFBUSxLQUFLLEtBQUssSUFBSSxXQUFXLENBQUMsVUFBVSxHQUFHLEVBQUUsRUFBRSxDQUFDO1lBQ2xFLE9BQU8sSUFBSSxD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
206
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGxzLWRldGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvZGV0ZWN0aW9uL2RldGVjdG9ycy90bHMtZGV0ZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFLSCxPQUFPLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRTlELHdCQUF3QjtBQUN4QixPQUFPLEVBQUUsYUFBYSxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFFakcseURBQXlEO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUMxRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxnREFBZ0QsQ0FBQztBQUVuRjs7R0FFRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBQ3RCOztPQUVHO2FBQ3FCLHdCQUFtQixHQUFHLENBQUMsQ0FBQztJQUVoRDs7T0FFRzthQUNZLHNCQUFpQixHQUFHLElBQUksR0FBRyxFQUE2QixDQUFDO0lBRXhFOztPQUVHO0lBQ0ssa0JBQWtCLENBQUMsT0FBdUY7UUFDaEgsT0FBTyxHQUFHLE9BQU8sQ0FBQyxRQUFRLElBQUksU0FBUyxJQUFJLE9BQU8sQ0FBQyxVQUFVLElBQUksQ0FBQyxLQUFLLE9BQU8sQ0FBQyxNQUFNLElBQUksU0FBUyxJQUFJLE9BQU8sQ0FBQyxRQUFRLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDaEksQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLE1BQWMsRUFBRSxPQUEyQjtRQUNoRCwrQkFBK0I7UUFDL0IsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLFdBQVcsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ3BELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELGdD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
@@ -12,7 +12,7 @@ import { DetectionFragmentManager } from './utils/fragment-manager.js';
12
12
  export class ProtocolDetector {
13
13
  constructor() {
14
14
  this.fragmentManager = new DetectionFragmentManager();
15
- this.tlsDetector = new TlsDetector(this.fragmentManager);
15
+ this.tlsDetector = new TlsDetector();
16
16
  this.httpDetector = new HttpDetector(this.fragmentManager);
17
17
  }
18
18
  static getInstance() {
@@ -170,4 +170,4 @@ export class ProtocolDetector {
170
170
  };
171
171
  }
172
172
  }
173
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdG9jb2wtZGV0ZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kZXRlY3Rpb24vcHJvdG9jb2wtZGV0ZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUlILE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDNUQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFdkU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZ0JBQWdCO0lBTTNCO1FBQ0UsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLHdCQUF3QixFQUFFLENBQUM7UUFDdEQsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDekQsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVPLE1BQU0sQ0FBQyxXQUFXO1FBQ3hCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbkIsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLGdCQUFnQixFQUFFLENBQUM7UUFDekMsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN2QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFjLEVBQUUsT0FBMkI7UUFDN0QsT0FBTyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUM1RCxDQUFDO0lBRU8sS0FBSyxDQUFDLGNBQWMsQ0FBQyxNQUFjLEVBQUUsT0FBMkI7UUFDdEUscUJBQXFCO1FBQ3JCLElBQUksQ0FBQyxNQUFNLElBQUksTUFBTSxD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
173
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdG9jb2wtZGV0ZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kZXRlY3Rpb24vcHJvdG9jb2wtZGV0ZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUlILE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDNUQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFdkU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZ0JBQWdCO0lBTTNCO1FBQ0UsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLHdCQUF3QixFQUFFLENBQUM7UUFDdEQsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFTyxNQUFNLENBQUMsV0FBVztRQUN4QixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3pDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDdkIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBYyxFQUFFLE9BQTJCO1FBQzdELE9BQU8sSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVPLEtBQUssQ0FBQyxjQUFjLENBQUMsTUFBYyxFQUFFLE9BQTJCO1FBQ3RFLHFCQUFxQjtRQUNyQixJQUFJLENBQUMsTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDbkMsT0FBTztnQkFDTCxRQUFRLEVBQUUsU0FBUztnQkFDbkIsY0FBYyxFQUFFLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRTtnQkFDdkMsVUFBVSxFQUFFLElBQUk7YUFDakIsQ0FBQztRQUNKLENBQUM7UUFFRCwwQ0FBMEM7UUFDMUMsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQ3ZDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztZQUMzRCxJQUFJLFNBQVMsRUFBRSxDQUFDO2dCQUNkLE9BQU8sU0FBUyxDQUFDO1lBQ25CLENBQUM7UUFDSCxDQUFDO1FBRUQscUJBQXFCO1FBQ3JCLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUN4QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDN0QsSUFBSSxVQUFVLEVBQUUsQ0FBQztnQkFDZixPQUFPLFVBQVUsQ0FBQztZQUNwQixDQUFDO1FBQ0gsQ0FBQztRQUVELHVCQUF1QjtRQUN2QixPQUFPO1lBQ0wsUUFBUSxFQUFFLFNBQVM7WUFDbkIsY0FBYyxFQUFFLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRTtZQUN2QyxVQUFVLEVBQUUsSUFBSTtTQUNqQixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7T0FHRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLENBQ3ZDLE1BQWMsRUFDZCxZQUFvQixFQUNwQixPQUEyQjtRQUUzQixtQ0FBbUM7UUFDbkMsTUFBTSxPQUFPLEdBQXVCO1lBQ2xDLEVBQUUsRUFBRSxZQUFZO1lBQ2hCLFFBQVEsRUFBRSxTQUFTO1lBQ25CLFVBQVUsRUFBRSxDQUFDO1lBQ2IsTUFBTSxFQUFFLFNBQVM7WUFDakIsUUFBUSxFQUFFLENBQUM7WUFDWCxTQUFTLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTtTQUN0QixDQUFDO1FBRUYsT0FBTyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMseUJBQXlCLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNoRixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUM1QixNQUFjLEVBQ2QsT0FBMkIsRUFDM0IsT0FBMkI7UUFFM0IsT0FBTyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMseUJBQXlCLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNoRixDQUFDO0lBRU8sS0FBSyxDQUFDLHlCQUF5QixDQUNyQyxNQUFjLEVBQ2QsT0FBMkIsRUFDM0IsT0FBMkI7UUFFM0IscUJBQXFCO1FBQ3JCLElBQUksQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNuQyxPQUFPO2dCQUNMLFFBQVEsRUFBRSxTQUFTO2dCQUNuQixjQUFjLEVBQUUsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFO2dCQUN2QyxVQUFVLEVBQUUsSUFBSTthQUNqQixDQUFDO1FBQ0osQ0FBQztRQUVELHdDQUF3QztRQUN4QyxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDdkMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQzVFLElBQUksTUFBTSxFQUFFLENBQUM7Z0JBQ1gsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztRQUNILENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDeEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQzdFLElBQUksTUFBTSxFQUFFLENBQUM7Z0JBQ1gsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztRQUNILENBQUM7UUFFRCwyQkFBMkI7UUFDM0IsT0FBTztZQUNMLFFBQVEsRUFBRSxTQUFTO1lBQ25CLGNBQWMsRUFBRSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUU7WUFDdkMsVUFBVSxFQUFFLEtBQUs7WUFDakIsV0FBVyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQ25CLElBQUksQ0FBQyxXQUFXLENBQUMsZUFBZSxFQUFFLEVBQ2xDLElBQUksQ0FBQyxZQUFZLENBQUMsZUFBZSxFQUFFLENBQ3BDO1NBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxPQUFPO1FBQ1osSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ3ZDLENBQUM7SUFFTyxlQUFlO1FBQ3JCLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDakMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLE9BQU87UUFDWixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDckMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFXLENBQUM7SUFDOUIsQ0FBQztJQUVPLGVBQWU7UUFDckIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxTQUFpQixLQUFLO1FBQzlDLDREQUE0RDtRQUM1RCxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQy9DLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxhQUFhLENBQUMsY0FBbUI7UUFDdEMsT0FBTyxjQUFjLENBQUMsTUFBTSxJQUFJLGNBQWMsQ0FBQyxHQUFHLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQztJQUM1RSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLGtCQUFrQixDQUFDLE1BTXpCO1FBQ0Msa0NBQWtDO1FBQ2xDLElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3BCLE9BQU8sTUFBTSxDQUFDLFFBQVEsQ0FBQztRQUN6QixDQUFDO1FBRUQseUNBQXlDO1FBQ3pDLE1BQU0sRUFBRSxRQUFRLEdBQUcsU0FBUyxFQUFFLFVBQVUsR0FBRyxDQUFDLEVBQUUsTUFBTSxHQUFHLFNBQVMsRUFBRSxRQUFRLEdBQUcsQ0FBQyxFQUFFLEdBQUcsTUFBTSxDQUFDO1FBQzFGLE9BQU8sR0FBRyxRQUFRLElBQUksVUFBVSxJQUFJLE1BQU0sSUFBSSxRQUFRLEVBQUUsQ0FBQztJQUMzRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsdUJBQXVCLENBQUMsTUFNOUI7UUFDQyxPQUFPO1lBQ0wsRUFBRSxFQUFFLE1BQU0sQ0FBQyxRQUFRO1lBQ25CLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxJQUFJLFNBQVM7WUFDdEMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVLElBQUksQ0FBQztZQUNsQyxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU0sSUFBSSxTQUFTO1lBQ2xDLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxJQUFJLENBQUM7WUFDOUIsU0FBUyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7U0FDdEIsQ0FBQztJQUNKLENBQUM7Q0FDRiJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartproxy",
3
- "version": "21.1.0",
3
+ "version": "21.1.2",
4
4
  "private": false,
5
5
  "description": "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.",
6
6
  "main": "dist_ts/index.js",
@@ -8,12 +8,6 @@
8
8
  "type": "module",
9
9
  "author": "Lossless GmbH",
10
10
  "license": "MIT",
11
- "scripts": {
12
- "test": "(tstest test/**/test*.ts --verbose --timeout 60 --logfile)",
13
- "build": "(tsbuild tsfolders --allowimplicitany)",
14
- "format": "(gitzone format)",
15
- "buildDocs": "tsdoc"
16
- },
17
11
  "devDependencies": {
18
12
  "@git.zone/tsbuild": "^2.6.4",
19
13
  "@git.zone/tsrun": "^1.2.44",
@@ -82,13 +76,10 @@
82
76
  "bugs": {
83
77
  "url": "https://code.foss.global/push.rocks/smartproxy/issues"
84
78
  },
85
- "pnpm": {
86
- "overrides": {},
87
- "onlyBuiltDependencies": [
88
- "esbuild",
89
- "mongodb-memory-server",
90
- "puppeteer"
91
- ]
92
- },
93
- "packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
94
- }
79
+ "scripts": {
80
+ "test": "(tstest test/**/test*.ts --verbose --timeout 60 --logfile)",
81
+ "build": "(tsbuild tsfolders --allowimplicitany)",
82
+ "format": "(gitzone format)",
83
+ "buildDocs": "tsdoc"
84
+ }
85
+ }
@@ -1,120 +1,223 @@
1
1
  /**
2
- * TLS Protocol Detector
3
- *
4
- * Simplified TLS detection using the new architecture
2
+ * TLS protocol detector
5
3
  */
6
4
 
5
+ // TLS detector doesn't need plugins imports
7
6
  import type { IProtocolDetector } from '../models/interfaces.js';
8
- import type { IDetectionResult, IDetectionOptions } from '../models/detection-types.js';
9
- import type { IProtocolDetectionResult, IConnectionContext } from '../../protocols/common/types.js';
10
- import { QuickProtocolDetector } from './quick-detector.js';
11
- import { RoutingExtractor } from './routing-extractor.js';
12
- import { DetectionFragmentManager } from '../utils/fragment-manager.js';
7
+ import type { IDetectionResult, IDetectionOptions, IConnectionInfo } from '../models/detection-types.js';
8
+ import { readUInt16BE } from '../utils/buffer-utils.js';
9
+ import { tlsVersionToString } from '../utils/parser-utils.js';
10
+
11
+ // Import from protocols
12
+ import { TlsRecordType, TlsHandshakeType, TlsExtensionType } from '../../protocols/tls/index.js';
13
+
14
+ // Import TLS utilities for SNI extraction from protocols
15
+ import { SniExtraction } from '../../protocols/tls/sni/sni-extraction.js';
16
+ import { ClientHelloParser } from '../../protocols/tls/sni/client-hello-parser.js';
13
17
 
14
18
  /**
15
- * Simplified TLS detector
19
+ * TLS detector implementation
16
20
  */
17
21
  export class TlsDetector implements IProtocolDetector {
18
- private quickDetector = new QuickProtocolDetector();
19
- private fragmentManager: DetectionFragmentManager;
22
+ /**
23
+ * Minimum bytes needed to identify TLS (record header)
24
+ */
25
+ private static readonly MIN_TLS_HEADER_SIZE = 5;
20
26
 
21
- constructor(fragmentManager?: DetectionFragmentManager) {
22
- this.fragmentManager = fragmentManager || new DetectionFragmentManager();
27
+
28
+ /**
29
+ * Detect TLS protocol from buffer
30
+ */
31
+ detect(buffer: Buffer, options?: IDetectionOptions): IDetectionResult | null {
32
+ // Check if buffer is too small
33
+ if (buffer.length < TlsDetector.MIN_TLS_HEADER_SIZE) {
34
+ return null;
35
+ }
36
+
37
+ // Check if this is a TLS record
38
+ if (!this.isTlsRecord(buffer)) {
39
+ return null;
40
+ }
41
+
42
+ // Extract basic TLS info
43
+ const recordType = buffer[0];
44
+ const tlsMajor = buffer[1];
45
+ const tlsMinor = buffer[2];
46
+ const recordLength = readUInt16BE(buffer, 3);
47
+
48
+ // Initialize connection info
49
+ const connectionInfo: IConnectionInfo = {
50
+ protocol: 'tls',
51
+ tlsVersion: tlsVersionToString(tlsMajor, tlsMinor) || undefined
52
+ };
53
+
54
+ // If it's a handshake, try to extract more info
55
+ if (recordType === TlsRecordType.HANDSHAKE && buffer.length >= 6) {
56
+ const handshakeType = buffer[5];
57
+
58
+ // For ClientHello, extract SNI and other info
59
+ if (handshakeType === TlsHandshakeType.CLIENT_HELLO) {
60
+ // Check if we have the complete handshake
61
+ const totalRecordLength = recordLength + 5; // Including TLS header
62
+ if (buffer.length >= totalRecordLength) {
63
+ // Extract SNI using existing logic
64
+ const sni = SniExtraction.extractSNI(buffer);
65
+ if (sni) {
66
+ connectionInfo.domain = sni;
67
+ connectionInfo.sni = sni;
68
+ }
69
+
70
+ // Parse ClientHello for additional info
71
+ const parseResult = ClientHelloParser.parseClientHello(buffer);
72
+ if (parseResult.isValid) {
73
+ // Extract ALPN if present
74
+ const alpnExtension = parseResult.extensions.find(
75
+ ext => ext.type === TlsExtensionType.APPLICATION_LAYER_PROTOCOL_NEGOTIATION
76
+ );
77
+
78
+ if (alpnExtension) {
79
+ connectionInfo.alpn = this.parseAlpnExtension(alpnExtension.data);
80
+ }
81
+
82
+ // Store cipher suites if needed
83
+ if (parseResult.cipherSuites && options?.extractFullHeaders) {
84
+ connectionInfo.cipherSuites = this.parseCipherSuites(parseResult.cipherSuites);
85
+ }
86
+ }
87
+
88
+ // Return complete result
89
+ return {
90
+ protocol: 'tls',
91
+ connectionInfo,
92
+ remainingBuffer: buffer.length > totalRecordLength
93
+ ? buffer.subarray(totalRecordLength)
94
+ : undefined,
95
+ isComplete: true
96
+ };
97
+ } else {
98
+ // Incomplete handshake
99
+ return {
100
+ protocol: 'tls',
101
+ connectionInfo,
102
+ isComplete: false,
103
+ bytesNeeded: totalRecordLength
104
+ };
105
+ }
106
+ }
107
+ }
108
+
109
+ // For other TLS record types, just return basic info
110
+ return {
111
+ protocol: 'tls',
112
+ connectionInfo,
113
+ isComplete: true,
114
+ remainingBuffer: buffer.length > recordLength + 5
115
+ ? buffer.subarray(recordLength + 5)
116
+ : undefined
117
+ };
23
118
  }
24
119
 
25
120
  /**
26
121
  * Check if buffer can be handled by this detector
27
122
  */
28
123
  canHandle(buffer: Buffer): boolean {
29
- const result = this.quickDetector.quickDetect(buffer);
30
- return result.protocol === 'tls' && result.confidence > 50;
124
+ return buffer.length >= TlsDetector.MIN_TLS_HEADER_SIZE &&
125
+ this.isTlsRecord(buffer);
31
126
  }
32
127
 
33
128
  /**
34
129
  * Get minimum bytes needed for detection
35
130
  */
36
131
  getMinimumBytes(): number {
37
- return 5; // TLS record header
132
+ return TlsDetector.MIN_TLS_HEADER_SIZE;
38
133
  }
39
134
 
40
135
  /**
41
- * Detect TLS protocol from buffer
136
+ * Check if buffer contains a valid TLS record
42
137
  */
43
- detect(buffer: Buffer, options?: IDetectionOptions): IDetectionResult | null {
44
- // Quick detection first
45
- const quickResult = this.quickDetector.quickDetect(buffer);
138
+ private isTlsRecord(buffer: Buffer): boolean {
139
+ const recordType = buffer[0];
46
140
 
47
- if (quickResult.protocol !== 'tls' || quickResult.confidence < 50) {
48
- return null;
49
- }
141
+ // Check for valid record type
142
+ const validTypes = [
143
+ TlsRecordType.CHANGE_CIPHER_SPEC,
144
+ TlsRecordType.ALERT,
145
+ TlsRecordType.HANDSHAKE,
146
+ TlsRecordType.APPLICATION_DATA,
147
+ TlsRecordType.HEARTBEAT
148
+ ];
50
149
 
51
- // Extract TLS version for compatibility
52
- let tlsVersion: string | undefined;
53
- if (buffer.length >= 3) {
54
- const versionByte = buffer[2];
55
- switch (versionByte) {
56
- case 0x00: tlsVersion = 'SSLv3'; break;
57
- case 0x01: tlsVersion = 'TLSv1.0'; break;
58
- case 0x02: tlsVersion = 'TLSv1.1'; break;
59
- case 0x03: tlsVersion = 'TLSv1.2'; break;
60
- case 0x04: tlsVersion = 'TLSv1.3'; break;
61
- }
150
+ if (!validTypes.includes(recordType)) {
151
+ return false;
62
152
  }
63
153
 
64
- // If we don't need domain extraction, we can return early
65
- if (quickResult.confidence >= 95 && !options?.extractFullHeaders) {
66
- return {
67
- protocol: 'tls',
68
- connectionInfo: {
69
- protocol: 'tls',
70
- tlsVersion: tlsVersion as any
71
- },
72
- isComplete: true
73
- };
154
+ // Check TLS version bytes (should be 0x03 0x0X)
155
+ if (buffer[1] !== 0x03) {
156
+ return false;
74
157
  }
75
158
 
76
- // Extract routing information if needed
77
- const routing = RoutingExtractor.extract(buffer, 'tls');
159
+ // Check record length is reasonable
160
+ const recordLength = readUInt16BE(buffer, 3);
161
+ if (recordLength > 16384) { // Max TLS record size
162
+ return false;
163
+ }
78
164
 
79
- return {
80
- protocol: 'tls',
81
- connectionInfo: {
82
- protocol: 'tls',
83
- domain: routing?.domain,
84
- sni: routing?.domain,
85
- tlsVersion: tlsVersion as any
86
- },
87
- isComplete: !quickResult.requiresMoreData,
88
- bytesNeeded: quickResult.requiresMoreData ? buffer.length + 100 : undefined
89
- };
165
+ return true;
90
166
  }
91
167
 
92
168
  /**
93
- * Handle fragmented detection
169
+ * Parse ALPN extension data
94
170
  */
95
- detectWithContext(
96
- buffer: Buffer,
97
- context: IConnectionContext,
98
- options?: IDetectionOptions
99
- ): IDetectionResult | null {
100
- const handler = this.fragmentManager.getHandler('tls');
101
- const connectionId = DetectionFragmentManager.createConnectionId(context);
171
+ private parseAlpnExtension(data: Buffer): string[] {
172
+ const protocols: string[] = [];
102
173
 
103
- // Add fragment
104
- const result = handler.addFragment(connectionId, buffer);
174
+ if (data.length < 2) {
175
+ return protocols;
176
+ }
105
177
 
106
- if (result.error) {
107
- handler.complete(connectionId);
108
- return null;
178
+ const listLength = readUInt16BE(data, 0);
179
+ let offset = 2;
180
+
181
+ while (offset < Math.min(2 + listLength, data.length)) {
182
+ const protoLength = data[offset];
183
+ offset++;
184
+
185
+ if (offset + protoLength <= data.length) {
186
+ const protocol = data.subarray(offset, offset + protoLength).toString('ascii');
187
+ protocols.push(protocol);
188
+ offset += protoLength;
189
+ } else {
190
+ break;
191
+ }
109
192
  }
110
193
 
111
- // Try detection on accumulated buffer
112
- const detectResult = this.detect(result.buffer!, options);
194
+ return protocols;
195
+ }
196
+
197
+ /**
198
+ * Parse cipher suites
199
+ */
200
+ private parseCipherSuites(cipherData: Buffer): number[] {
201
+ const suites: number[] = [];
113
202
 
114
- if (detectResult && detectResult.isComplete) {
115
- handler.complete(connectionId);
203
+ for (let i = 0; i < cipherData.length - 1; i += 2) {
204
+ const suite = readUInt16BE(cipherData, i);
205
+ suites.push(suite);
116
206
  }
117
207
 
118
- return detectResult;
208
+ return suites;
209
+ }
210
+
211
+ /**
212
+ * Detect with context for fragmented data
213
+ */
214
+ detectWithContext(
215
+ buffer: Buffer,
216
+ _context: { sourceIp?: string; sourcePort?: number; destIp?: string; destPort?: number },
217
+ options?: IDetectionOptions
218
+ ): IDetectionResult | null {
219
+ // This method is deprecated - TLS detection should use the fragment manager
220
+ // from the parent detector system, not maintain its own fragments
221
+ return this.detect(buffer, options);
119
222
  }
120
223
  }
@@ -21,7 +21,7 @@ export class ProtocolDetector {
21
21
 
22
22
  constructor() {
23
23
  this.fragmentManager = new DetectionFragmentManager();
24
- this.tlsDetector = new TlsDetector(this.fragmentManager);
24
+ this.tlsDetector = new TlsDetector();
25
25
  this.httpDetector = new HttpDetector(this.fragmentManager);
26
26
  }
27
27
 
@@ -120,10 +120,28 @@ export class ProtocolDetector {
120
120
  };
121
121
  }
122
122
 
123
+ const connectionId = DetectionFragmentManager.createConnectionId(context);
124
+
123
125
  // First peek to determine protocol type
124
126
  if (this.tlsDetector.canHandle(buffer)) {
125
- const result = this.tlsDetector.detectWithContext(buffer, context, options);
127
+ // Handle TLS with fragment accumulation
128
+ const handler = this.fragmentManager.getHandler('tls');
129
+ const fragmentResult = handler.addFragment(connectionId, buffer);
130
+
131
+ if (fragmentResult.error) {
132
+ handler.complete(connectionId);
133
+ return {
134
+ protocol: 'unknown',
135
+ connectionInfo: { protocol: 'unknown' },
136
+ isComplete: true
137
+ };
138
+ }
139
+
140
+ const result = this.tlsDetector.detect(fragmentResult.buffer!, options);
126
141
  if (result) {
142
+ if (result.isComplete) {
143
+ handler.complete(connectionId);
144
+ }
127
145
  return result;
128
146
  }
129
147
  }
@@ -173,13 +191,25 @@ export class ProtocolDetector {
173
191
  /**
174
192
  * Clean up old connection tracking entries
175
193
  *
176
- * @param maxAge Maximum age in milliseconds (default: 30 seconds)
194
+ * @param _maxAge Maximum age in milliseconds (default: 30 seconds)
177
195
  */
178
- static cleanupConnections(maxAge: number = 30000): void {
196
+ static cleanupConnections(_maxAge: number = 30000): void {
179
197
  // Cleanup is now handled internally by the fragment manager
180
198
  this.getInstance().fragmentManager.cleanup();
181
199
  }
182
200
 
201
+ /**
202
+ * Clean up fragments for a specific connection
203
+ */
204
+ static cleanupConnection(context: IConnectionContext): void {
205
+ const instance = this.getInstance();
206
+ const connectionId = DetectionFragmentManager.createConnectionId(context);
207
+
208
+ // Clean up both TLS and HTTP fragments for this connection
209
+ instance.fragmentManager.getHandler('tls').complete(connectionId);
210
+ instance.fragmentManager.getHandler('http').complete(connectionId);
211
+ }
212
+
183
213
  /**
184
214
  * Extract domain from connection info
185
215
  */
@@ -5,6 +5,7 @@ import { connectionLogDeduplicator } from '../../core/utils/log-deduplicator.js'
5
5
  import { LifecycleComponent } from '../../core/utils/lifecycle-component.js';
6
6
  import { cleanupSocket } from '../../core/utils/socket-utils.js';
7
7
  import { WrappedSocket } from '../../core/models/wrapped-socket.js';
8
+ import { ProtocolDetector } from '../../detection/index.js';
8
9
  import type { SmartProxy } from './smart-proxy.js';
9
10
 
10
11
  /**
@@ -323,6 +324,18 @@ export class ConnectionManager extends LifecycleComponent {
323
324
  this.smartProxy.metricsCollector.removeConnection(record.id);
324
325
  }
325
326
 
327
+ // Clean up protocol detection fragments
328
+ const context = ProtocolDetector.createConnectionContext({
329
+ sourceIp: record.remoteIP,
330
+ sourcePort: record.incoming?.remotePort || 0,
331
+ destIp: record.incoming?.localAddress || '',
332
+ destPort: record.localPort,
333
+ socketId: record.id
334
+ });
335
+
336
+ // Clean up any pending detection fragments for this connection
337
+ ProtocolDetector.cleanupConnection(context);
338
+
326
339
  if (record.cleanupTimer) {
327
340
  clearTimeout(record.cleanupTimer);
328
341
  record.cleanupTimer = undefined;
@@ -303,18 +303,18 @@ export class RouteConnectionHandler {
303
303
 
304
304
  // Handler for processing initial data (after potential PROXY protocol)
305
305
  const processInitialData = async (chunk: Buffer) => {
306
- // Use ProtocolDetector to identify protocol
307
- const connectionId = ProtocolDetector.createConnectionId({
306
+ // Create connection context for protocol detection
307
+ const context = ProtocolDetector.createConnectionContext({
308
308
  sourceIp: record.remoteIP,
309
- sourcePort: socket.remotePort,
310
- destIp: socket.localAddress,
311
- destPort: socket.localPort,
309
+ sourcePort: socket.remotePort || 0,
310
+ destIp: socket.localAddress || '',
311
+ destPort: socket.localPort || 0,
312
312
  socketId: record.id
313
313
  });
314
314
 
315
- const detectionResult = await ProtocolDetector.detectWithConnectionTracking(
315
+ const detectionResult = await ProtocolDetector.detectWithContext(
316
316
  chunk,
317
- connectionId,
317
+ context,
318
318
  { extractFullHeaders: false } // Only extract essential info for routing
319
319
  );
320
320