@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 +9 -0
- package/dist_ts/detection/detectors/tls-detector.d.ts +35 -13
- package/dist_ts/detection/detectors/tls-detector.js +176 -76
- package/dist_ts/detection/protocol-detector.js +2 -2
- package/package.json +8 -17
- package/ts/detection/detectors/tls-detector.ts +178 -75
- package/ts/detection/protocol-detector.ts +34 -4
- package/ts/proxies/smart-proxy/connection-manager.ts +13 -0
- package/ts/proxies/smart-proxy/route-connection-handler.ts +7 -7
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
|
|
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
|
-
*
|
|
7
|
+
* TLS detector implementation
|
|
12
8
|
*/
|
|
13
9
|
export declare class TlsDetector implements IProtocolDetector {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
*
|
|
35
|
+
* Check if buffer contains a valid TLS record
|
|
27
36
|
*/
|
|
28
|
-
|
|
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
|
-
*
|
|
47
|
+
* Detect with context for fragmented data
|
|
31
48
|
*/
|
|
32
|
-
detectWithContext(buffer: Buffer, context:
|
|
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
|
|
3
|
-
*
|
|
4
|
-
* Simplified TLS detection using the new architecture
|
|
2
|
+
* TLS protocol detector
|
|
5
3
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
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
|
-
*
|
|
12
|
+
* TLS detector implementation
|
|
11
13
|
*/
|
|
12
14
|
export class TlsDetector {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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
|
|
120
|
+
return TlsDetector.MIN_TLS_HEADER_SIZE;
|
|
29
121
|
}
|
|
30
122
|
/**
|
|
31
|
-
*
|
|
123
|
+
* Check if buffer contains a valid TLS record
|
|
32
124
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
185
|
+
* Detect with context for fragmented data
|
|
88
186
|
*/
|
|
89
187
|
detectWithContext(buffer, context, options) {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
|
203
|
+
return result;
|
|
104
204
|
}
|
|
105
205
|
}
|
|
106
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
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(
|
|
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,
|
|
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.
|
|
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
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
|
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
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
*
|
|
19
|
+
* TLS detector implementation
|
|
16
20
|
*/
|
|
17
21
|
export class TlsDetector implements IProtocolDetector {
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Minimum bytes needed to identify TLS (record header)
|
|
24
|
+
*/
|
|
25
|
+
private static readonly MIN_TLS_HEADER_SIZE = 5;
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
30
|
-
|
|
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
|
|
132
|
+
return TlsDetector.MIN_TLS_HEADER_SIZE;
|
|
38
133
|
}
|
|
39
134
|
|
|
40
135
|
/**
|
|
41
|
-
*
|
|
136
|
+
* Check if buffer contains a valid TLS record
|
|
42
137
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const quickResult = this.quickDetector.quickDetect(buffer);
|
|
138
|
+
private isTlsRecord(buffer: Buffer): boolean {
|
|
139
|
+
const recordType = buffer[0];
|
|
46
140
|
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
//
|
|
65
|
-
if (
|
|
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
|
-
//
|
|
77
|
-
const
|
|
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
|
-
*
|
|
169
|
+
* Parse ALPN extension data
|
|
94
170
|
*/
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
104
|
-
|
|
174
|
+
if (data.length < 2) {
|
|
175
|
+
return protocols;
|
|
176
|
+
}
|
|
105
177
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
112
|
-
|
|
194
|
+
return protocols;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Parse cipher suites
|
|
199
|
+
*/
|
|
200
|
+
private parseCipherSuites(cipherData: Buffer): number[] {
|
|
201
|
+
const suites: number[] = [];
|
|
113
202
|
|
|
114
|
-
|
|
115
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
194
|
+
* @param _maxAge Maximum age in milliseconds (default: 30 seconds)
|
|
177
195
|
*/
|
|
178
|
-
static cleanupConnections(
|
|
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
|
-
//
|
|
307
|
-
const
|
|
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.
|
|
315
|
+
const detectionResult = await ProtocolDetector.detectWithContext(
|
|
316
316
|
chunk,
|
|
317
|
-
|
|
317
|
+
context,
|
|
318
318
|
{ extractFullHeaders: false } // Only extract essential info for routing
|
|
319
319
|
);
|
|
320
320
|
|