@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 +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 +203 -71
- package/ts/detection/protocol-detector.ts +1 -1
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.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
|
-
"
|
|
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,252 @@
|
|
|
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, 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
|
-
*
|
|
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
|
+
* 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
|
-
|
|
30
|
-
|
|
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
|
|
143
|
+
return TlsDetector.MIN_TLS_HEADER_SIZE;
|
|
38
144
|
}
|
|
39
145
|
|
|
40
146
|
/**
|
|
41
|
-
*
|
|
147
|
+
* Check if buffer contains a valid TLS record
|
|
42
148
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const quickResult = this.quickDetector.quickDetect(buffer);
|
|
149
|
+
private isTlsRecord(buffer: Buffer): boolean {
|
|
150
|
+
const recordType = buffer[0];
|
|
46
151
|
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
*
|
|
223
|
+
* Detect with context for fragmented data
|
|
94
224
|
*/
|
|
95
225
|
detectWithContext(
|
|
96
226
|
buffer: Buffer,
|
|
97
|
-
context:
|
|
227
|
+
context: { sourceIp?: string; sourcePort?: number; destIp?: string; destPort?: number },
|
|
98
228
|
options?: IDetectionOptions
|
|
99
229
|
): IDetectionResult | null {
|
|
100
|
-
const
|
|
101
|
-
const connectionId = DetectionFragmentManager.createConnectionId(context);
|
|
230
|
+
const connectionId = this.createConnectionId(context);
|
|
102
231
|
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
//
|
|
112
|
-
|
|
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
|
-
|
|
115
|
-
|
|
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
|
|
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(
|
|
24
|
+
this.tlsDetector = new TlsDetector();
|
|
25
25
|
this.httpDetector = new HttpDetector(this.fragmentManager);
|
|
26
26
|
}
|
|
27
27
|
|