@push.rocks/smartproxy 21.1.0 → 21.1.1

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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdG9jb2wtZGV0ZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kZXRlY3Rpb24vcHJvdG9jb2wtZGV0ZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUlILE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDNUQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFdkU7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZ0JBQWdCO0lBTTNCO1FBQ0UsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLHdCQUF3QixFQUFFLENBQUM7UUFDdEQsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFTyxNQUFNLENBQUMsV0FBVztRQUN4QixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3pDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDdkIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBYyxFQUFFLE9BQTJCO1FBQzdELE9BQU8sSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVPLEtBQUssQ0FBQyxjQUFjLENBQUMsTUFBYyxFQUFFLE9BQTJCO1FBQ3RFLHFCQUFxQjtRQUNyQixJQUFJLENBQUMsTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxF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
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.1",
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,252 @@
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, BufferAccumulator } 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
+ * Fragment tracking for incomplete handshakes
29
+ */
30
+ private static fragmentedBuffers = new Map<string, BufferAccumulator>();
31
+
32
+ /**
33
+ * Create connection ID from context
34
+ */
35
+ private createConnectionId(context: { sourceIp?: string; sourcePort?: number; destIp?: string; destPort?: number }): string {
36
+ return `${context.sourceIp || 'unknown'}:${context.sourcePort || 0}->${context.destIp || 'unknown'}:${context.destPort || 0}`;
37
+ }
38
+
39
+ /**
40
+ * Detect TLS protocol from buffer
41
+ */
42
+ detect(buffer: Buffer, options?: IDetectionOptions): IDetectionResult | null {
43
+ // Check if buffer is too small
44
+ if (buffer.length < TlsDetector.MIN_TLS_HEADER_SIZE) {
45
+ return null;
46
+ }
47
+
48
+ // Check if this is a TLS record
49
+ if (!this.isTlsRecord(buffer)) {
50
+ return null;
51
+ }
52
+
53
+ // Extract basic TLS info
54
+ const recordType = buffer[0];
55
+ const tlsMajor = buffer[1];
56
+ const tlsMinor = buffer[2];
57
+ const recordLength = readUInt16BE(buffer, 3);
58
+
59
+ // Initialize connection info
60
+ const connectionInfo: IConnectionInfo = {
61
+ protocol: 'tls',
62
+ tlsVersion: tlsVersionToString(tlsMajor, tlsMinor) || undefined
63
+ };
64
+
65
+ // If it's a handshake, try to extract more info
66
+ if (recordType === TlsRecordType.HANDSHAKE && buffer.length >= 6) {
67
+ const handshakeType = buffer[5];
68
+
69
+ // For ClientHello, extract SNI and other info
70
+ if (handshakeType === TlsHandshakeType.CLIENT_HELLO) {
71
+ // Check if we have the complete handshake
72
+ const totalRecordLength = recordLength + 5; // Including TLS header
73
+ if (buffer.length >= totalRecordLength) {
74
+ // Extract SNI using existing logic
75
+ const sni = SniExtraction.extractSNI(buffer);
76
+ if (sni) {
77
+ connectionInfo.domain = sni;
78
+ connectionInfo.sni = sni;
79
+ }
80
+
81
+ // Parse ClientHello for additional info
82
+ const parseResult = ClientHelloParser.parseClientHello(buffer);
83
+ if (parseResult.isValid) {
84
+ // Extract ALPN if present
85
+ const alpnExtension = parseResult.extensions.find(
86
+ ext => ext.type === TlsExtensionType.APPLICATION_LAYER_PROTOCOL_NEGOTIATION
87
+ );
88
+
89
+ if (alpnExtension) {
90
+ connectionInfo.alpn = this.parseAlpnExtension(alpnExtension.data);
91
+ }
92
+
93
+ // Store cipher suites if needed
94
+ if (parseResult.cipherSuites && options?.extractFullHeaders) {
95
+ connectionInfo.cipherSuites = this.parseCipherSuites(parseResult.cipherSuites);
96
+ }
97
+ }
98
+
99
+ // Return complete result
100
+ return {
101
+ protocol: 'tls',
102
+ connectionInfo,
103
+ remainingBuffer: buffer.length > totalRecordLength
104
+ ? buffer.subarray(totalRecordLength)
105
+ : undefined,
106
+ isComplete: true
107
+ };
108
+ } else {
109
+ // Incomplete handshake
110
+ return {
111
+ protocol: 'tls',
112
+ connectionInfo,
113
+ isComplete: false,
114
+ bytesNeeded: totalRecordLength
115
+ };
116
+ }
117
+ }
118
+ }
119
+
120
+ // For other TLS record types, just return basic info
121
+ return {
122
+ protocol: 'tls',
123
+ connectionInfo,
124
+ isComplete: true,
125
+ remainingBuffer: buffer.length > recordLength + 5
126
+ ? buffer.subarray(recordLength + 5)
127
+ : undefined
128
+ };
23
129
  }
24
130
 
25
131
  /**
26
132
  * Check if buffer can be handled by this detector
27
133
  */
28
134
  canHandle(buffer: Buffer): boolean {
29
- const result = this.quickDetector.quickDetect(buffer);
30
- return result.protocol === 'tls' && result.confidence > 50;
135
+ return buffer.length >= TlsDetector.MIN_TLS_HEADER_SIZE &&
136
+ this.isTlsRecord(buffer);
31
137
  }
32
138
 
33
139
  /**
34
140
  * Get minimum bytes needed for detection
35
141
  */
36
142
  getMinimumBytes(): number {
37
- return 5; // TLS record header
143
+ return TlsDetector.MIN_TLS_HEADER_SIZE;
38
144
  }
39
145
 
40
146
  /**
41
- * Detect TLS protocol from buffer
147
+ * Check if buffer contains a valid TLS record
42
148
  */
43
- detect(buffer: Buffer, options?: IDetectionOptions): IDetectionResult | null {
44
- // Quick detection first
45
- const quickResult = this.quickDetector.quickDetect(buffer);
149
+ private isTlsRecord(buffer: Buffer): boolean {
150
+ const recordType = buffer[0];
46
151
 
47
- if (quickResult.protocol !== 'tls' || quickResult.confidence < 50) {
48
- return null;
152
+ // Check for valid record type
153
+ const validTypes = [
154
+ TlsRecordType.CHANGE_CIPHER_SPEC,
155
+ TlsRecordType.ALERT,
156
+ TlsRecordType.HANDSHAKE,
157
+ TlsRecordType.APPLICATION_DATA,
158
+ TlsRecordType.HEARTBEAT
159
+ ];
160
+
161
+ if (!validTypes.includes(recordType)) {
162
+ return false;
49
163
  }
50
164
 
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
- }
165
+ // Check TLS version bytes (should be 0x03 0x0X)
166
+ if (buffer[1] !== 0x03) {
167
+ return false;
62
168
  }
63
169
 
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
- };
170
+ // Check record length is reasonable
171
+ const recordLength = readUInt16BE(buffer, 3);
172
+ if (recordLength > 16384) { // Max TLS record size
173
+ return false;
74
174
  }
75
175
 
76
- // Extract routing information if needed
77
- const routing = RoutingExtractor.extract(buffer, 'tls');
176
+ return true;
177
+ }
178
+
179
+ /**
180
+ * Parse ALPN extension data
181
+ */
182
+ private parseAlpnExtension(data: Buffer): string[] {
183
+ const protocols: string[] = [];
78
184
 
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
- };
185
+ if (data.length < 2) {
186
+ return protocols;
187
+ }
188
+
189
+ const listLength = readUInt16BE(data, 0);
190
+ let offset = 2;
191
+
192
+ while (offset < Math.min(2 + listLength, data.length)) {
193
+ const protoLength = data[offset];
194
+ offset++;
195
+
196
+ if (offset + protoLength <= data.length) {
197
+ const protocol = data.subarray(offset, offset + protoLength).toString('ascii');
198
+ protocols.push(protocol);
199
+ offset += protoLength;
200
+ } else {
201
+ break;
202
+ }
203
+ }
204
+
205
+ return protocols;
206
+ }
207
+
208
+ /**
209
+ * Parse cipher suites
210
+ */
211
+ private parseCipherSuites(cipherData: Buffer): number[] {
212
+ const suites: number[] = [];
213
+
214
+ for (let i = 0; i < cipherData.length - 1; i += 2) {
215
+ const suite = readUInt16BE(cipherData, i);
216
+ suites.push(suite);
217
+ }
218
+
219
+ return suites;
90
220
  }
91
221
 
92
222
  /**
93
- * Handle fragmented detection
223
+ * Detect with context for fragmented data
94
224
  */
95
225
  detectWithContext(
96
226
  buffer: Buffer,
97
- context: IConnectionContext,
227
+ context: { sourceIp?: string; sourcePort?: number; destIp?: string; destPort?: number },
98
228
  options?: IDetectionOptions
99
229
  ): IDetectionResult | null {
100
- const handler = this.fragmentManager.getHandler('tls');
101
- const connectionId = DetectionFragmentManager.createConnectionId(context);
230
+ const connectionId = this.createConnectionId(context);
102
231
 
103
- // Add fragment
104
- const result = handler.addFragment(connectionId, buffer);
105
-
106
- if (result.error) {
107
- handler.complete(connectionId);
108
- return null;
232
+ // Get or create buffer accumulator for this connection
233
+ let accumulator = TlsDetector.fragmentedBuffers.get(connectionId);
234
+ if (!accumulator) {
235
+ accumulator = new BufferAccumulator();
236
+ TlsDetector.fragmentedBuffers.set(connectionId, accumulator);
109
237
  }
110
238
 
111
- // Try detection on accumulated buffer
112
- const detectResult = this.detect(result.buffer!, options);
239
+ // Add new data
240
+ accumulator.append(buffer);
241
+
242
+ // Try detection on accumulated data
243
+ const result = this.detect(accumulator.getBuffer(), options);
113
244
 
114
- if (detectResult && detectResult.isComplete) {
115
- handler.complete(connectionId);
245
+ // If detection is complete or we have too much data, clean up
246
+ if (result?.isComplete || accumulator.length() > 65536) {
247
+ TlsDetector.fragmentedBuffers.delete(connectionId);
116
248
  }
117
249
 
118
- return detectResult;
250
+ return result;
119
251
  }
120
252
  }
@@ -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