@push.rocks/smartproxy 22.6.0 → 23.1.0

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.
Files changed (196) hide show
  1. package/changelog.md +18 -0
  2. package/dist_rust/{rustproxy → rustproxy_linux_amd64} +0 -0
  3. package/dist_rust/rustproxy_linux_arm64 +0 -0
  4. package/dist_ts/00_commitinfo_data.js +1 -1
  5. package/dist_ts/index.d.ts +0 -1
  6. package/dist_ts/index.js +1 -3
  7. package/dist_ts/plugins.d.ts +2 -1
  8. package/dist_ts/plugins.js +3 -2
  9. package/dist_ts/proxies/index.d.ts +0 -1
  10. package/dist_ts/proxies/index.js +1 -3
  11. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  12. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +9 -21
  13. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +83 -212
  14. package/dist_ts/proxies/smart-proxy/smart-proxy.js +2 -3
  15. package/npmextra.json +3 -0
  16. package/package.json +13 -11
  17. package/readme.md +35 -31
  18. package/ts/00_commitinfo_data.ts +1 -1
  19. package/ts/index.ts +0 -3
  20. package/ts/plugins.ts +2 -0
  21. package/ts/proxies/index.ts +0 -3
  22. package/ts/proxies/smart-proxy/models/route-types.ts +0 -2
  23. package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +102 -233
  24. package/ts/proxies/smart-proxy/smart-proxy.ts +1 -2
  25. package/dist_ts/common/eventUtils.d.ts +0 -14
  26. package/dist_ts/common/eventUtils.js +0 -20
  27. package/dist_ts/common/types.d.ts +0 -82
  28. package/dist_ts/common/types.js +0 -15
  29. package/dist_ts/core/utils/event-system.d.ts +0 -200
  30. package/dist_ts/core/utils/event-system.js +0 -224
  31. package/dist_ts/core/utils/event-utils.d.ts +0 -15
  32. package/dist_ts/core/utils/event-utils.js +0 -11
  33. package/dist_ts/core/utils/route-manager.d.ts +0 -88
  34. package/dist_ts/core/utils/route-manager.js +0 -342
  35. package/dist_ts/core/utils/route-utils.d.ts +0 -28
  36. package/dist_ts/core/utils/route-utils.js +0 -67
  37. package/dist_ts/detection/detectors/http-detector-v2.d.ts +0 -33
  38. package/dist_ts/detection/detectors/http-detector-v2.js +0 -87
  39. package/dist_ts/detection/detectors/tls-detector-v2.d.ts +0 -33
  40. package/dist_ts/detection/detectors/tls-detector-v2.js +0 -80
  41. package/dist_ts/detection/protocol-detector-v2.d.ts +0 -46
  42. package/dist_ts/detection/protocol-detector-v2.js +0 -116
  43. package/dist_ts/forwarding/config/forwarding-types.d.ts +0 -42
  44. package/dist_ts/forwarding/config/forwarding-types.js +0 -18
  45. package/dist_ts/forwarding/config/index.d.ts +0 -9
  46. package/dist_ts/forwarding/config/index.js +0 -10
  47. package/dist_ts/forwarding/factory/forwarding-factory.d.ts +0 -25
  48. package/dist_ts/forwarding/factory/forwarding-factory.js +0 -172
  49. package/dist_ts/forwarding/factory/index.d.ts +0 -4
  50. package/dist_ts/forwarding/factory/index.js +0 -5
  51. package/dist_ts/forwarding/handlers/base-handler.d.ts +0 -62
  52. package/dist_ts/forwarding/handlers/base-handler.js +0 -121
  53. package/dist_ts/forwarding/handlers/http-handler.d.ts +0 -30
  54. package/dist_ts/forwarding/handlers/http-handler.js +0 -143
  55. package/dist_ts/forwarding/handlers/https-passthrough-handler.d.ts +0 -29
  56. package/dist_ts/forwarding/handlers/https-passthrough-handler.js +0 -156
  57. package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.d.ts +0 -36
  58. package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +0 -276
  59. package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.d.ts +0 -35
  60. package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +0 -261
  61. package/dist_ts/forwarding/handlers/index.d.ts +0 -8
  62. package/dist_ts/forwarding/handlers/index.js +0 -9
  63. package/dist_ts/forwarding/index.d.ts +0 -13
  64. package/dist_ts/forwarding/index.js +0 -16
  65. package/dist_ts/http/index.d.ts +0 -5
  66. package/dist_ts/http/index.js +0 -8
  67. package/dist_ts/http/models/http-types.d.ts +0 -6
  68. package/dist_ts/http/models/http-types.js +0 -7
  69. package/dist_ts/http/router/index.d.ts +0 -8
  70. package/dist_ts/http/router/index.js +0 -7
  71. package/dist_ts/http/router/proxy-router.d.ts +0 -115
  72. package/dist_ts/http/router/proxy-router.js +0 -325
  73. package/dist_ts/http/router/route-router.d.ts +0 -108
  74. package/dist_ts/http/router/route-router.js +0 -393
  75. package/dist_ts/protocols/tls/constants.d.ts +0 -122
  76. package/dist_ts/protocols/tls/constants.js +0 -135
  77. package/dist_ts/protocols/tls/parser.d.ts +0 -53
  78. package/dist_ts/protocols/tls/parser.js +0 -294
  79. package/dist_ts/protocols/tls/types.d.ts +0 -65
  80. package/dist_ts/protocols/tls/types.js +0 -5
  81. package/dist_ts/proxies/http-proxy/certificate-manager.d.ts +0 -95
  82. package/dist_ts/proxies/http-proxy/certificate-manager.js +0 -214
  83. package/dist_ts/proxies/http-proxy/connection-pool.d.ts +0 -47
  84. package/dist_ts/proxies/http-proxy/connection-pool.js +0 -195
  85. package/dist_ts/proxies/http-proxy/context-creator.d.ts +0 -34
  86. package/dist_ts/proxies/http-proxy/context-creator.js +0 -108
  87. package/dist_ts/proxies/http-proxy/default-certificates.d.ts +0 -54
  88. package/dist_ts/proxies/http-proxy/default-certificates.js +0 -127
  89. package/dist_ts/proxies/http-proxy/function-cache.d.ts +0 -95
  90. package/dist_ts/proxies/http-proxy/function-cache.js +0 -215
  91. package/dist_ts/proxies/http-proxy/handlers/index.d.ts +0 -4
  92. package/dist_ts/proxies/http-proxy/handlers/index.js +0 -6
  93. package/dist_ts/proxies/http-proxy/handlers/redirect-handler.d.ts +0 -18
  94. package/dist_ts/proxies/http-proxy/handlers/redirect-handler.js +0 -78
  95. package/dist_ts/proxies/http-proxy/handlers/static-handler.d.ts +0 -19
  96. package/dist_ts/proxies/http-proxy/handlers/static-handler.js +0 -211
  97. package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -117
  98. package/dist_ts/proxies/http-proxy/http-proxy.js +0 -521
  99. package/dist_ts/proxies/http-proxy/http-request-handler.d.ts +0 -40
  100. package/dist_ts/proxies/http-proxy/http-request-handler.js +0 -257
  101. package/dist_ts/proxies/http-proxy/http2-request-handler.d.ts +0 -24
  102. package/dist_ts/proxies/http-proxy/http2-request-handler.js +0 -201
  103. package/dist_ts/proxies/http-proxy/index.d.ts +0 -14
  104. package/dist_ts/proxies/http-proxy/index.js +0 -16
  105. package/dist_ts/proxies/http-proxy/models/http-types.d.ts +0 -117
  106. package/dist_ts/proxies/http-proxy/models/http-types.js +0 -92
  107. package/dist_ts/proxies/http-proxy/models/index.d.ts +0 -5
  108. package/dist_ts/proxies/http-proxy/models/index.js +0 -6
  109. package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -75
  110. package/dist_ts/proxies/http-proxy/models/types.js +0 -35
  111. package/dist_ts/proxies/http-proxy/request-handler.d.ts +0 -97
  112. package/dist_ts/proxies/http-proxy/request-handler.js +0 -737
  113. package/dist_ts/proxies/http-proxy/security-manager.d.ts +0 -98
  114. package/dist_ts/proxies/http-proxy/security-manager.js +0 -341
  115. package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +0 -50
  116. package/dist_ts/proxies/http-proxy/websocket-handler.js +0 -505
  117. package/dist_ts/proxies/nftables-proxy/index.d.ts +0 -6
  118. package/dist_ts/proxies/nftables-proxy/index.js +0 -7
  119. package/dist_ts/proxies/nftables-proxy/models/errors.d.ts +0 -15
  120. package/dist_ts/proxies/nftables-proxy/models/errors.js +0 -28
  121. package/dist_ts/proxies/nftables-proxy/models/index.d.ts +0 -5
  122. package/dist_ts/proxies/nftables-proxy/models/index.js +0 -6
  123. package/dist_ts/proxies/nftables-proxy/models/interfaces.d.ts +0 -75
  124. package/dist_ts/proxies/nftables-proxy/models/interfaces.js +0 -5
  125. package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +0 -124
  126. package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +0 -1374
  127. package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +0 -9
  128. package/dist_ts/proxies/nftables-proxy/utils/index.js +0 -12
  129. package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +0 -66
  130. package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +0 -131
  131. package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +0 -39
  132. package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +0 -112
  133. package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +0 -59
  134. package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +0 -130
  135. package/dist_ts/proxies/smart-proxy/acme-state-manager.d.ts +0 -42
  136. package/dist_ts/proxies/smart-proxy/acme-state-manager.js +0 -101
  137. package/dist_ts/proxies/smart-proxy/cert-store.d.ts +0 -10
  138. package/dist_ts/proxies/smart-proxy/cert-store.js +0 -72
  139. package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +0 -164
  140. package/dist_ts/proxies/smart-proxy/certificate-manager.js +0 -745
  141. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +0 -128
  142. package/dist_ts/proxies/smart-proxy/connection-manager.js +0 -689
  143. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +0 -43
  144. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +0 -180
  145. package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +0 -98
  146. package/dist_ts/proxies/smart-proxy/metrics-collector.js +0 -355
  147. package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +0 -82
  148. package/dist_ts/proxies/smart-proxy/nftables-manager.js +0 -237
  149. package/dist_ts/proxies/smart-proxy/port-manager.d.ts +0 -117
  150. package/dist_ts/proxies/smart-proxy/port-manager.js +0 -318
  151. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +0 -60
  152. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +0 -1407
  153. package/dist_ts/proxies/smart-proxy/route-manager.d.ts +0 -112
  154. package/dist_ts/proxies/smart-proxy/route-manager.js +0 -453
  155. package/dist_ts/proxies/smart-proxy/route-orchestrator.d.ts +0 -56
  156. package/dist_ts/proxies/smart-proxy/route-orchestrator.js +0 -204
  157. package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +0 -23
  158. package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +0 -104
  159. package/dist_ts/proxies/smart-proxy/security-manager.d.ts +0 -74
  160. package/dist_ts/proxies/smart-proxy/security-manager.js +0 -227
  161. package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +0 -36
  162. package/dist_ts/proxies/smart-proxy/throughput-tracker.js +0 -115
  163. package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +0 -48
  164. package/dist_ts/proxies/smart-proxy/timeout-manager.js +0 -158
  165. package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +0 -50
  166. package/dist_ts/proxies/smart-proxy/tls-manager.js +0 -110
  167. package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +0 -161
  168. package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +0 -282
  169. package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +0 -73
  170. package/dist_ts/proxies/smart-proxy/utils/route-validators.js +0 -259
  171. package/dist_ts/routing/router/proxy-router.d.ts +0 -115
  172. package/dist_ts/routing/router/proxy-router.js +0 -325
  173. package/dist_ts/routing/router/route-router.d.ts +0 -108
  174. package/dist_ts/routing/router/route-router.js +0 -393
  175. package/dist_ts/tls/alerts/index.d.ts +0 -4
  176. package/dist_ts/tls/alerts/index.js +0 -5
  177. package/dist_ts/tls/alerts/tls-alert.d.ts +0 -150
  178. package/dist_ts/tls/alerts/tls-alert.js +0 -226
  179. package/dist_ts/tls/sni/client-hello-parser.d.ts +0 -100
  180. package/dist_ts/tls/sni/client-hello-parser.js +0 -464
  181. package/dist_ts/tls/sni/sni-extraction.d.ts +0 -58
  182. package/dist_ts/tls/sni/sni-extraction.js +0 -275
  183. package/dist_ts/tls/utils/index.d.ts +0 -4
  184. package/dist_ts/tls/utils/index.js +0 -5
  185. package/dist_ts/tls/utils/tls-utils.d.ts +0 -49
  186. package/dist_ts/tls/utils/tls-utils.js +0 -75
  187. package/ts/proxies/nftables-proxy/index.ts +0 -6
  188. package/ts/proxies/nftables-proxy/models/errors.ts +0 -30
  189. package/ts/proxies/nftables-proxy/models/index.ts +0 -5
  190. package/ts/proxies/nftables-proxy/models/interfaces.ts +0 -94
  191. package/ts/proxies/nftables-proxy/nftables-proxy.ts +0 -1754
  192. package/ts/proxies/nftables-proxy/utils/index.ts +0 -38
  193. package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +0 -162
  194. package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +0 -125
  195. package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +0 -156
  196. package/ts/proxies/smart-proxy/rust-binary-locator.ts +0 -112
@@ -1,464 +0,0 @@
1
- import { Buffer } from 'buffer';
2
- import { TlsRecordType, TlsHandshakeType, TlsExtensionType } from '../../protocols/tls/index.js';
3
- import { TlsUtils } from '../utils/tls-utils.js';
4
- /**
5
- * Class for parsing TLS ClientHello messages
6
- */
7
- export class ClientHelloParser {
8
- // Buffer for handling fragmented ClientHello messages
9
- static { this.fragmentedBuffers = new Map(); }
10
- static { this.fragmentTimeout = 1000; } // ms to wait for fragments before cleanup
11
- /**
12
- * Clean up expired fragments
13
- */
14
- static cleanupExpiredFragments() {
15
- const now = Date.now();
16
- for (const [connectionId, info] of this.fragmentedBuffers.entries()) {
17
- if (now - info.timestamp > this.fragmentTimeout) {
18
- this.fragmentedBuffers.delete(connectionId);
19
- }
20
- }
21
- }
22
- /**
23
- * Handles potential fragmented ClientHello messages by buffering and reassembling
24
- * TLS record fragments that might span multiple TCP packets.
25
- *
26
- * @param buffer The current buffer fragment
27
- * @param connectionId Unique identifier for the connection
28
- * @param logger Optional logging function
29
- * @returns A complete buffer if reassembly is successful, or undefined if more fragments are needed
30
- */
31
- static handleFragmentedClientHello(buffer, connectionId, logger) {
32
- const log = logger || (() => { });
33
- // Periodically clean up expired fragments
34
- this.cleanupExpiredFragments();
35
- // Check if we've seen this connection before
36
- if (!this.fragmentedBuffers.has(connectionId)) {
37
- // New connection, start with this buffer
38
- this.fragmentedBuffers.set(connectionId, {
39
- buffer,
40
- timestamp: Date.now(),
41
- connectionId
42
- });
43
- // Evaluate if this buffer already contains a complete ClientHello
44
- try {
45
- if (buffer.length >= 5) {
46
- // Get the record length from TLS header
47
- const recordLength = (buffer[3] << 8) + buffer[4] + 5; // +5 for the TLS record header itself
48
- log(`Initial buffer size: ${buffer.length}, expected record length: ${recordLength}`);
49
- // Check if this buffer already contains a complete TLS record
50
- if (buffer.length >= recordLength) {
51
- log(`Initial buffer contains complete ClientHello, length: ${buffer.length}`);
52
- return buffer;
53
- }
54
- }
55
- else {
56
- log(`Initial buffer too small (${buffer.length} bytes), needs at least 5 bytes for TLS header`);
57
- }
58
- }
59
- catch (e) {
60
- log(`Error checking initial buffer completeness: ${e}`);
61
- }
62
- log(`Started buffering connection ${connectionId}, initial size: ${buffer.length}`);
63
- return undefined; // Need more fragments
64
- }
65
- else {
66
- // Existing connection, append this buffer
67
- const existingInfo = this.fragmentedBuffers.get(connectionId);
68
- const newBuffer = Buffer.concat([existingInfo.buffer, buffer]);
69
- // Update the buffer and timestamp
70
- this.fragmentedBuffers.set(connectionId, {
71
- ...existingInfo,
72
- buffer: newBuffer,
73
- timestamp: Date.now()
74
- });
75
- log(`Appended to buffer for ${connectionId}, new size: ${newBuffer.length}`);
76
- // Check if we now have a complete ClientHello
77
- try {
78
- if (newBuffer.length >= 5) {
79
- // Get the record length from TLS header
80
- const recordLength = (newBuffer[3] << 8) + newBuffer[4] + 5; // +5 for the TLS record header itself
81
- log(`Reassembled buffer size: ${newBuffer.length}, expected record length: ${recordLength}`);
82
- // Check if we have a complete TLS record now
83
- if (newBuffer.length >= recordLength) {
84
- log(`Assembled complete ClientHello, length: ${newBuffer.length}, needed: ${recordLength}`);
85
- // Extract the complete TLS record (might be followed by more data)
86
- const completeRecord = newBuffer.slice(0, recordLength);
87
- // Check if this record is indeed a ClientHello (type 1) at position 5
88
- if (completeRecord.length > 5 &&
89
- completeRecord[5] === TlsHandshakeType.CLIENT_HELLO) {
90
- log(`Verified record is a ClientHello handshake message`);
91
- // Complete message received, remove from tracking
92
- this.fragmentedBuffers.delete(connectionId);
93
- return completeRecord;
94
- }
95
- else {
96
- log(`Record is complete but not a ClientHello handshake, continuing to buffer`);
97
- // This might be another TLS record type preceding the ClientHello
98
- // Try checking for a ClientHello starting at the end of this record
99
- if (newBuffer.length > recordLength + 5) {
100
- const nextRecordType = newBuffer[recordLength];
101
- log(`Next record type: ${nextRecordType} (looking for ${TlsRecordType.HANDSHAKE})`);
102
- if (nextRecordType === TlsRecordType.HANDSHAKE) {
103
- const handshakeType = newBuffer[recordLength + 5];
104
- log(`Next handshake type: ${handshakeType} (looking for ${TlsHandshakeType.CLIENT_HELLO})`);
105
- if (handshakeType === TlsHandshakeType.CLIENT_HELLO) {
106
- // Found a ClientHello in the next record, return the entire buffer
107
- log(`Found ClientHello in subsequent record, returning full buffer`);
108
- this.fragmentedBuffers.delete(connectionId);
109
- return newBuffer;
110
- }
111
- }
112
- }
113
- }
114
- }
115
- }
116
- }
117
- catch (e) {
118
- log(`Error checking reassembled buffer completeness: ${e}`);
119
- }
120
- return undefined; // Still need more fragments
121
- }
122
- }
123
- /**
124
- * Parses a TLS ClientHello message and extracts all components
125
- *
126
- * @param buffer The buffer containing the ClientHello message
127
- * @param logger Optional logging function
128
- * @returns Parsed ClientHello or undefined if parsing failed
129
- */
130
- static parseClientHello(buffer, logger) {
131
- const log = logger || (() => { });
132
- const result = {
133
- isValid: false,
134
- hasSessionId: false,
135
- extensions: [],
136
- hasSessionTicket: false,
137
- hasPsk: false,
138
- hasEarlyData: false
139
- };
140
- try {
141
- // Check basic validity
142
- if (buffer.length < 5) {
143
- result.error = 'Buffer too small for TLS record header';
144
- return result;
145
- }
146
- // Check record type (must be HANDSHAKE)
147
- if (buffer[0] !== TlsRecordType.HANDSHAKE) {
148
- result.error = `Not a TLS handshake record: ${buffer[0]}`;
149
- return result;
150
- }
151
- // Get TLS version from record header
152
- const majorVersion = buffer[1];
153
- const minorVersion = buffer[2];
154
- result.version = [majorVersion, minorVersion];
155
- log(`TLS record version: ${majorVersion}.${minorVersion}`);
156
- // Parse record length (bytes 3-4, big-endian)
157
- const recordLength = (buffer[3] << 8) + buffer[4];
158
- log(`Record length: ${recordLength}`);
159
- // Validate record length against buffer size
160
- if (buffer.length < recordLength + 5) {
161
- result.error = 'Buffer smaller than expected record length';
162
- return result;
163
- }
164
- // Start of handshake message in the buffer
165
- let pos = 5;
166
- // Check handshake type (must be CLIENT_HELLO)
167
- if (buffer[pos] !== TlsHandshakeType.CLIENT_HELLO) {
168
- result.error = `Not a ClientHello message: ${buffer[pos]}`;
169
- return result;
170
- }
171
- // Skip handshake type (1 byte)
172
- pos += 1;
173
- // Parse handshake length (3 bytes, big-endian)
174
- const handshakeLength = (buffer[pos] << 16) + (buffer[pos + 1] << 8) + buffer[pos + 2];
175
- log(`Handshake length: ${handshakeLength}`);
176
- // Skip handshake length (3 bytes)
177
- pos += 3;
178
- // Check client version (2 bytes)
179
- const clientMajorVersion = buffer[pos];
180
- const clientMinorVersion = buffer[pos + 1];
181
- log(`Client version: ${clientMajorVersion}.${clientMinorVersion}`);
182
- // Skip client version (2 bytes)
183
- pos += 2;
184
- // Extract client random (32 bytes)
185
- if (pos + 32 > buffer.length) {
186
- result.error = 'Buffer too small for client random';
187
- return result;
188
- }
189
- result.random = buffer.slice(pos, pos + 32);
190
- log(`Client random: ${result.random.toString('hex')}`);
191
- // Skip client random (32 bytes)
192
- pos += 32;
193
- // Parse session ID
194
- if (pos + 1 > buffer.length) {
195
- result.error = 'Buffer too small for session ID length';
196
- return result;
197
- }
198
- const sessionIdLength = buffer[pos];
199
- log(`Session ID length: ${sessionIdLength}`);
200
- pos += 1;
201
- result.hasSessionId = sessionIdLength > 0;
202
- if (sessionIdLength > 0) {
203
- if (pos + sessionIdLength > buffer.length) {
204
- result.error = 'Buffer too small for session ID';
205
- return result;
206
- }
207
- result.sessionId = buffer.slice(pos, pos + sessionIdLength);
208
- log(`Session ID: ${result.sessionId.toString('hex')}`);
209
- }
210
- // Skip session ID
211
- pos += sessionIdLength;
212
- // Check if we have enough bytes left for cipher suites
213
- if (pos + 2 > buffer.length) {
214
- result.error = 'Buffer too small for cipher suites length';
215
- return result;
216
- }
217
- // Parse cipher suites length (2 bytes, big-endian)
218
- const cipherSuitesLength = (buffer[pos] << 8) + buffer[pos + 1];
219
- log(`Cipher suites length: ${cipherSuitesLength}`);
220
- pos += 2;
221
- // Extract cipher suites
222
- if (pos + cipherSuitesLength > buffer.length) {
223
- result.error = 'Buffer too small for cipher suites';
224
- return result;
225
- }
226
- result.cipherSuites = buffer.slice(pos, pos + cipherSuitesLength);
227
- // Skip cipher suites
228
- pos += cipherSuitesLength;
229
- // Check if we have enough bytes left for compression methods
230
- if (pos + 1 > buffer.length) {
231
- result.error = 'Buffer too small for compression methods length';
232
- return result;
233
- }
234
- // Parse compression methods length (1 byte)
235
- const compressionMethodsLength = buffer[pos];
236
- log(`Compression methods length: ${compressionMethodsLength}`);
237
- pos += 1;
238
- // Extract compression methods
239
- if (pos + compressionMethodsLength > buffer.length) {
240
- result.error = 'Buffer too small for compression methods';
241
- return result;
242
- }
243
- result.compressionMethods = buffer.slice(pos, pos + compressionMethodsLength);
244
- // Skip compression methods
245
- pos += compressionMethodsLength;
246
- // Check if we have enough bytes for extensions length
247
- if (pos + 2 > buffer.length) {
248
- // No extensions present - this is valid for older TLS versions
249
- result.isValid = true;
250
- return result;
251
- }
252
- // Parse extensions length (2 bytes, big-endian)
253
- const extensionsLength = (buffer[pos] << 8) + buffer[pos + 1];
254
- log(`Extensions length: ${extensionsLength}`);
255
- pos += 2;
256
- // Extensions end position
257
- const extensionsEnd = pos + extensionsLength;
258
- // Check if extensions length is valid
259
- if (extensionsEnd > buffer.length) {
260
- result.error = 'Extensions length exceeds buffer size';
261
- return result;
262
- }
263
- // Iterate through extensions
264
- const serverNames = [];
265
- while (pos + 4 <= extensionsEnd) {
266
- // Parse extension type (2 bytes, big-endian)
267
- const extensionType = (buffer[pos] << 8) + buffer[pos + 1];
268
- log(`Extension type: 0x${extensionType.toString(16).padStart(4, '0')}`);
269
- pos += 2;
270
- // Parse extension length (2 bytes, big-endian)
271
- const extensionLength = (buffer[pos] << 8) + buffer[pos + 1];
272
- log(`Extension length: ${extensionLength}`);
273
- pos += 2;
274
- // Extract extension data
275
- if (pos + extensionLength > extensionsEnd) {
276
- result.error = `Extension ${extensionType} data exceeds bounds`;
277
- return result;
278
- }
279
- const extensionData = buffer.slice(pos, pos + extensionLength);
280
- // Record all extensions
281
- result.extensions.push({
282
- type: extensionType,
283
- length: extensionLength,
284
- data: extensionData
285
- });
286
- // Track specific extension types
287
- if (extensionType === TlsExtensionType.SERVER_NAME) {
288
- // Server Name Indication (SNI)
289
- this.parseServerNameExtension(extensionData, serverNames, logger);
290
- }
291
- else if (extensionType === TlsExtensionType.SESSION_TICKET) {
292
- // Session ticket
293
- result.hasSessionTicket = true;
294
- }
295
- else if (extensionType === TlsExtensionType.PRE_SHARED_KEY) {
296
- // TLS 1.3 PSK
297
- result.hasPsk = true;
298
- }
299
- else if (extensionType === TlsExtensionType.EARLY_DATA) {
300
- // TLS 1.3 Early Data (0-RTT)
301
- result.hasEarlyData = true;
302
- }
303
- // Move to next extension
304
- pos += extensionLength;
305
- }
306
- // Store any server names found
307
- if (serverNames.length > 0) {
308
- result.serverNameList = serverNames;
309
- }
310
- // Mark as valid if we get here
311
- result.isValid = true;
312
- return result;
313
- }
314
- catch (error) {
315
- const errorMessage = error instanceof Error ? error.message : String(error);
316
- log(`Error parsing ClientHello: ${errorMessage}`);
317
- result.error = errorMessage;
318
- return result;
319
- }
320
- }
321
- /**
322
- * Parses the server name extension data and extracts hostnames
323
- *
324
- * @param data Extension data buffer
325
- * @param serverNames Array to populate with found server names
326
- * @param logger Optional logging function
327
- * @returns true if parsing succeeded
328
- */
329
- static parseServerNameExtension(data, serverNames, logger) {
330
- const log = logger || (() => { });
331
- try {
332
- // Need at least 2 bytes for server name list length
333
- if (data.length < 2) {
334
- log('SNI extension too small for server name list length');
335
- return false;
336
- }
337
- // Parse server name list length (2 bytes)
338
- const listLength = (data[0] << 8) + data[1];
339
- // Skip to first name entry
340
- let pos = 2;
341
- // End of list
342
- const listEnd = pos + listLength;
343
- // Validate length
344
- if (listEnd > data.length) {
345
- log('SNI server name list exceeds extension data');
346
- return false;
347
- }
348
- // Process all name entries
349
- while (pos + 3 <= listEnd) {
350
- // Name type (1 byte)
351
- const nameType = data[pos];
352
- pos += 1;
353
- // For hostname, type must be 0
354
- if (nameType !== 0) {
355
- // Skip this entry
356
- if (pos + 2 <= listEnd) {
357
- const nameLength = (data[pos] << 8) + data[pos + 1];
358
- pos += 2 + nameLength;
359
- continue;
360
- }
361
- else {
362
- log('Malformed SNI entry');
363
- return false;
364
- }
365
- }
366
- // Parse hostname length (2 bytes)
367
- if (pos + 2 > listEnd) {
368
- log('SNI extension truncated');
369
- return false;
370
- }
371
- const nameLength = (data[pos] << 8) + data[pos + 1];
372
- pos += 2;
373
- // Extract hostname
374
- if (pos + nameLength > listEnd) {
375
- log('SNI hostname truncated');
376
- return false;
377
- }
378
- // Extract the hostname as UTF-8
379
- try {
380
- const hostname = data.slice(pos, pos + nameLength).toString('utf8');
381
- log(`Found SNI hostname: ${hostname}`);
382
- serverNames.push(hostname);
383
- }
384
- catch (err) {
385
- log(`Error extracting hostname: ${err}`);
386
- }
387
- // Move to next entry
388
- pos += nameLength;
389
- }
390
- return serverNames.length > 0;
391
- }
392
- catch (error) {
393
- log(`Error parsing SNI extension: ${error}`);
394
- return false;
395
- }
396
- }
397
- /**
398
- * Determines if a ClientHello contains session resumption indicators
399
- *
400
- * @param buffer The ClientHello buffer
401
- * @param logger Optional logging function
402
- * @returns Session resumption result
403
- */
404
- static hasSessionResumption(buffer, logger) {
405
- const log = logger || (() => { });
406
- if (!TlsUtils.isClientHello(buffer)) {
407
- return { isResumption: false, hasSNI: false };
408
- }
409
- const parseResult = this.parseClientHello(buffer, logger);
410
- if (!parseResult.isValid) {
411
- log(`ClientHello parse failed: ${parseResult.error}`);
412
- return { isResumption: false, hasSNI: false };
413
- }
414
- // Check resumption indicators
415
- const hasSessionId = parseResult.hasSessionId;
416
- const hasSessionTicket = parseResult.hasSessionTicket;
417
- const hasPsk = parseResult.hasPsk;
418
- const hasEarlyData = parseResult.hasEarlyData;
419
- // Check for SNI
420
- const hasSNI = !!parseResult.serverNameList && parseResult.serverNameList.length > 0;
421
- // Consider it a resumption if any resumption mechanism is present
422
- const isResumption = hasSessionTicket || hasPsk || hasEarlyData ||
423
- (hasSessionId && !hasPsk); // Legacy resumption
424
- // Log details
425
- if (isResumption) {
426
- log('Session resumption detected: ' +
427
- (hasSessionTicket ? 'session ticket, ' : '') +
428
- (hasPsk ? 'PSK, ' : '') +
429
- (hasEarlyData ? 'early data, ' : '') +
430
- (hasSessionId ? 'session ID' : '') +
431
- (hasSNI ? ', with SNI' : ', without SNI'));
432
- }
433
- return { isResumption, hasSNI };
434
- }
435
- /**
436
- * Checks if a ClientHello appears to be from a tab reactivation
437
- *
438
- * @param buffer The ClientHello buffer
439
- * @param logger Optional logging function
440
- * @returns true if it appears to be a tab reactivation
441
- */
442
- static isTabReactivationHandshake(buffer, logger) {
443
- const log = logger || (() => { });
444
- if (!TlsUtils.isClientHello(buffer)) {
445
- return false;
446
- }
447
- // Parse the ClientHello
448
- const parseResult = this.parseClientHello(buffer, logger);
449
- if (!parseResult.isValid) {
450
- return false;
451
- }
452
- // Tab reactivation pattern: session identifier + (ticket or PSK) but no SNI
453
- const hasSessionId = parseResult.hasSessionId;
454
- const hasSessionTicket = parseResult.hasSessionTicket;
455
- const hasPsk = parseResult.hasPsk;
456
- const hasSNI = !!parseResult.serverNameList && parseResult.serverNameList.length > 0;
457
- if ((hasSessionId && (hasSessionTicket || hasPsk)) && !hasSNI) {
458
- log('Detected tab reactivation pattern: session resumption without SNI');
459
- return true;
460
- }
461
- return false;
462
- }
463
- }
464
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LWhlbGxvLXBhcnNlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Rscy9zbmkvY2xpZW50LWhlbGxvLXBhcnNlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQ2hDLE9BQU8sRUFDTCxhQUFhLEVBQ2IsZ0JBQWdCLEVBQ2hCLGdCQUFnQixFQUNqQixNQUFNLDhCQUE4QixDQUFDO0FBQ3RDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQW9EakQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8saUJBQWlCO0lBQzVCLHNEQUFzRDthQUN2QyxzQkFBaUIsR0FBc0MsSUFBSSxHQUFHLEVBQUUsQ0FBQzthQUNqRSxvQkFBZSxHQUFXLElBQUksQ0FBQyxHQUFDLDBDQUEwQztJQUV6Rjs7T0FFRztJQUNLLE1BQU0sQ0FBQyx1QkFBdUI7UUFDcEMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssTUFBTSxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsaUJBQWlCLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUNwRSxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztnQkFDaEQsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUM5QyxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNJLE1BQU0sQ0FBQywyQkFBMkIsQ0FDdkMsTUFBYyxFQUNkLFlBQW9CLEVBQ3BCLE1BQXVCO1FBRXZCLE1BQU0sR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDO1FBRWpDLDBDQUEwQztRQUMxQyxJQUFJ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
@@ -1,58 +0,0 @@
1
- import { Buffer } from 'buffer';
2
- import { type LoggerFunction } from './client-hello-parser.js';
3
- /**
4
- * Connection tracking information
5
- */
6
- export interface ConnectionInfo {
7
- sourceIp: string;
8
- sourcePort: number;
9
- destIp: string;
10
- destPort: number;
11
- timestamp?: number;
12
- }
13
- /**
14
- * Utilities for extracting SNI information from TLS handshakes
15
- */
16
- export declare class SniExtraction {
17
- /**
18
- * Extracts the SNI (Server Name Indication) from a TLS ClientHello message.
19
- *
20
- * @param buffer The buffer containing the TLS ClientHello message
21
- * @param logger Optional logging function
22
- * @returns The extracted server name or undefined if not found
23
- */
24
- static extractSNI(buffer: Buffer, logger?: LoggerFunction): string | undefined;
25
- /**
26
- * Attempts to extract SNI from the PSK extension in a TLS 1.3 ClientHello.
27
- *
28
- * In TLS 1.3, when a client attempts to resume a session, it may include
29
- * the server name in the PSK identity hint rather than in the SNI extension.
30
- *
31
- * @param buffer The buffer containing the TLS ClientHello message
32
- * @param logger Optional logging function
33
- * @returns The extracted server name or undefined if not found
34
- */
35
- static extractSNIFromPSKExtension(buffer: Buffer, logger?: LoggerFunction): string | undefined;
36
- /**
37
- * Main entry point for SNI extraction with support for fragmented messages
38
- * and session resumption edge cases.
39
- *
40
- * @param buffer The buffer containing TLS data
41
- * @param connectionInfo Connection tracking information
42
- * @param logger Optional logging function
43
- * @param cachedSni Optional previously cached SNI value
44
- * @returns The extracted server name or undefined
45
- */
46
- static extractSNIWithResumptionSupport(buffer: Buffer, connectionInfo?: ConnectionInfo, logger?: LoggerFunction, cachedSni?: string): string | undefined;
47
- /**
48
- * Unified method for processing a TLS packet and extracting SNI.
49
- * Main entry point for SNI extraction that handles all edge cases.
50
- *
51
- * @param buffer The buffer containing TLS data
52
- * @param connectionInfo Connection tracking information
53
- * @param logger Optional logging function
54
- * @param cachedSni Optional previously cached SNI value
55
- * @returns The extracted server name or undefined
56
- */
57
- static processTlsPacket(buffer: Buffer, connectionInfo: ConnectionInfo, logger?: LoggerFunction, cachedSni?: string): string | undefined;
58
- }