@push.rocks/smartproxy 19.6.2 → 19.6.7

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 (52) hide show
  1. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +4 -7
  2. package/dist_ts/proxies/smart-proxy/connection-manager.js +22 -22
  3. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +4 -3
  4. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +9 -9
  5. package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +68 -56
  6. package/dist_ts/proxies/smart-proxy/metrics-collector.js +226 -176
  7. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -0
  8. package/dist_ts/proxies/smart-proxy/models/metrics-types.d.ts +94 -48
  9. package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +4 -4
  10. package/dist_ts/proxies/smart-proxy/nftables-manager.js +6 -6
  11. package/dist_ts/proxies/smart-proxy/port-manager.d.ts +4 -7
  12. package/dist_ts/proxies/smart-proxy/port-manager.js +6 -9
  13. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -15
  14. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +128 -128
  15. package/dist_ts/proxies/smart-proxy/security-manager.d.ts +3 -3
  16. package/dist_ts/proxies/smart-proxy/security-manager.js +9 -9
  17. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +20 -13
  18. package/dist_ts/proxies/smart-proxy/smart-proxy.js +16 -13
  19. package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +36 -0
  20. package/dist_ts/proxies/smart-proxy/throughput-tracker.js +117 -0
  21. package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +4 -3
  22. package/dist_ts/proxies/smart-proxy/timeout-manager.js +16 -16
  23. package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +3 -3
  24. package/dist_ts/proxies/smart-proxy/tls-manager.js +12 -12
  25. package/package.json +8 -17
  26. package/readme.hints.md +0 -897
  27. package/readme.md +960 -54
  28. package/readme.plan.md +301 -562
  29. package/ts/proxies/smart-proxy/connection-manager.ts +23 -21
  30. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +9 -8
  31. package/ts/proxies/smart-proxy/metrics-collector.ts +277 -189
  32. package/ts/proxies/smart-proxy/models/interfaces.ts +7 -0
  33. package/ts/proxies/smart-proxy/models/metrics-types.ts +93 -41
  34. package/ts/proxies/smart-proxy/nftables-manager.ts +5 -5
  35. package/ts/proxies/smart-proxy/port-manager.ts +6 -14
  36. package/ts/proxies/smart-proxy/route-connection-handler.ts +136 -136
  37. package/ts/proxies/smart-proxy/security-manager.ts +8 -8
  38. package/ts/proxies/smart-proxy/smart-proxy.ts +26 -35
  39. package/ts/proxies/smart-proxy/throughput-tracker.ts +144 -0
  40. package/ts/proxies/smart-proxy/timeout-manager.ts +16 -15
  41. package/ts/proxies/smart-proxy/tls-manager.ts +11 -11
  42. package/readme.connections.md +0 -724
  43. package/readme.delete.md +0 -187
  44. package/readme.memory-leaks-fixed.md +0 -45
  45. package/readme.metrics.md +0 -591
  46. package/readme.monitoring.md +0 -202
  47. package/readme.proxy-chain-summary.md +0 -112
  48. package/readme.proxy-protocol-example.md +0 -462
  49. package/readme.proxy-protocol.md +0 -415
  50. package/readme.routing.md +0 -341
  51. package/readme.websocket-keepalive-config.md +0 -140
  52. package/readme.websocket-keepalive-fix.md +0 -63
@@ -1,415 +0,0 @@
1
- # SmartProxy PROXY Protocol and Proxy Chaining Documentation
2
-
3
- ## Overview
4
-
5
- SmartProxy implements support for the PROXY protocol v1 to enable proxy chaining and preserve real client IP addresses across multiple proxy layers. This documentation covers the implementation details, configuration, and usage patterns for proxy chaining scenarios.
6
-
7
- ## Architecture
8
-
9
- ### WrappedSocket Implementation
10
-
11
- The foundation of PROXY protocol support is the `WrappedSocket` class, which wraps regular `net.Socket` instances to provide transparent access to real client information when behind a proxy.
12
-
13
- ```typescript
14
- // ts/core/models/wrapped-socket.ts
15
- export class WrappedSocket {
16
- public readonly socket: plugins.net.Socket;
17
- private realClientIP?: string;
18
- private realClientPort?: number;
19
-
20
- constructor(
21
- socket: plugins.net.Socket,
22
- realClientIP?: string,
23
- realClientPort?: number
24
- ) {
25
- this.socket = socket;
26
- this.realClientIP = realClientIP;
27
- this.realClientPort = realClientPort;
28
-
29
- // Uses JavaScript Proxy to delegate all methods to underlying socket
30
- return new Proxy(this, {
31
- get(target, prop, receiver) {
32
- // Override specific properties
33
- if (prop === 'remoteAddress') {
34
- return target.remoteAddress;
35
- }
36
- if (prop === 'remotePort') {
37
- return target.remotePort;
38
- }
39
- // ... delegate other properties to underlying socket
40
- }
41
- });
42
- }
43
-
44
- get remoteAddress(): string | undefined {
45
- return this.realClientIP || this.socket.remoteAddress;
46
- }
47
-
48
- get remotePort(): number | undefined {
49
- return this.realClientPort || this.socket.remotePort;
50
- }
51
-
52
- get isFromTrustedProxy(): boolean {
53
- return !!this.realClientIP;
54
- }
55
- }
56
- ```
57
-
58
- ### Key Design Decisions
59
-
60
- 1. **All sockets are wrapped** - Every incoming connection is wrapped in a WrappedSocket, not just those from trusted proxies
61
- 2. **Proxy pattern for delegation** - Uses JavaScript Proxy to transparently delegate all Socket methods while allowing property overrides
62
- 3. **Not a Duplex stream** - Simple wrapper approach avoids complexity and infinite loops
63
- 4. **Trust-based parsing** - PROXY protocol parsing only occurs for connections from trusted proxy IPs
64
-
65
- ## Configuration
66
-
67
- ### Basic PROXY Protocol Configuration
68
-
69
- ```typescript
70
- const proxy = new SmartProxy({
71
- // List of trusted proxy IPs that can send PROXY protocol
72
- proxyIPs: ['10.0.0.1', '10.0.0.2', '192.168.1.0/24'],
73
-
74
- // Global option to accept PROXY protocol (defaults based on proxyIPs)
75
- acceptProxyProtocol: true,
76
-
77
- // Global option to send PROXY protocol to all targets
78
- sendProxyProtocol: false,
79
-
80
- routes: [
81
- {
82
- name: 'backend-app',
83
- match: { ports: 443, domains: 'app.example.com' },
84
- action: {
85
- type: 'forward',
86
- target: { host: 'backend.internal', port: 8443 },
87
- tls: { mode: 'passthrough' }
88
- }
89
- }
90
- ]
91
- });
92
- ```
93
-
94
- ### Proxy Chain Configuration
95
-
96
- Setting up two SmartProxies in a chain:
97
-
98
- ```typescript
99
- // Outer Proxy (Internet-facing)
100
- const outerProxy = new SmartProxy({
101
- proxyIPs: [], // No trusted proxies for outer proxy
102
- sendProxyProtocol: true, // Send PROXY protocol to inner proxy
103
-
104
- routes: [{
105
- name: 'to-inner-proxy',
106
- match: { ports: 443 },
107
- action: {
108
- type: 'forward',
109
- target: {
110
- host: 'inner-proxy.internal',
111
- port: 443
112
- },
113
- tls: { mode: 'passthrough' }
114
- }
115
- }]
116
- });
117
-
118
- // Inner Proxy (Backend-facing)
119
- const innerProxy = new SmartProxy({
120
- proxyIPs: ['outer-proxy.internal'], // Trust the outer proxy
121
- acceptProxyProtocol: true,
122
-
123
- routes: [{
124
- name: 'to-backend',
125
- match: { ports: 443, domains: 'app.example.com' },
126
- action: {
127
- type: 'forward',
128
- target: {
129
- host: 'backend.internal',
130
- port: 8080
131
- },
132
- tls: {
133
- mode: 'terminate',
134
- certificate: 'auto'
135
- }
136
- }
137
- }]
138
- });
139
- ```
140
-
141
- ## How Two SmartProxies Communicate
142
-
143
- ### Connection Flow
144
-
145
- 1. **Client connects to Outer Proxy**
146
- ```
147
- Client (203.0.113.45:54321) → Outer Proxy (1.2.3.4:443)
148
- ```
149
-
150
- 2. **Outer Proxy wraps the socket**
151
- ```typescript
152
- // In RouteConnectionHandler.handleConnection()
153
- const wrappedSocket = new WrappedSocket(socket);
154
- // At this point:
155
- // wrappedSocket.remoteAddress = '203.0.113.45'
156
- // wrappedSocket.remotePort = 54321
157
- ```
158
-
159
- 3. **Outer Proxy forwards to Inner Proxy**
160
- - Creates new connection to inner proxy
161
- - If `sendProxyProtocol` is enabled, prepends PROXY protocol header:
162
- ```
163
- PROXY TCP4 203.0.113.45 1.2.3.4 54321 443\r\n
164
- [Original TLS/HTTP data follows]
165
- ```
166
-
167
- 4. **Inner Proxy receives connection**
168
- - Sees connection from outer proxy IP
169
- - Checks if IP is in `proxyIPs` list
170
- - If trusted, parses PROXY protocol header
171
- - Updates WrappedSocket with real client info:
172
- ```typescript
173
- wrappedSocket.setProxyInfo('203.0.113.45', 54321);
174
- ```
175
-
176
- 5. **Inner Proxy routes based on real client IP**
177
- - Security checks use real client IP
178
- - Connection records track real client IP
179
- - Backend sees requests from the original client IP
180
-
181
- ### Connection Record Tracking
182
-
183
- ```typescript
184
- // In ConnectionManager
185
- interface IConnectionRecord {
186
- id: string;
187
- incoming: WrappedSocket; // Wrapped socket with real client info
188
- outgoing: net.Socket | null;
189
- remoteIP: string; // Real client IP from PROXY protocol or direct connection
190
- localPort: number;
191
- // ... other fields
192
- }
193
- ```
194
-
195
- ## Implementation Details
196
-
197
- ### Socket Wrapping in Route Handler
198
-
199
- ```typescript
200
- // ts/proxies/smart-proxy/route-connection-handler.ts
201
- public handleConnection(socket: plugins.net.Socket): void {
202
- const remoteIP = socket.remoteAddress || '';
203
-
204
- // Always wrap the socket to prepare for potential PROXY protocol
205
- const wrappedSocket = new WrappedSocket(socket);
206
-
207
- // If this is from a trusted proxy, log it
208
- if (this.settings.proxyIPs?.includes(remoteIP)) {
209
- logger.log('debug', `Connection from trusted proxy ${remoteIP}, PROXY protocol parsing will be enabled`);
210
- }
211
-
212
- // Create connection record with wrapped socket
213
- const record = this.connectionManager.createConnection(wrappedSocket);
214
-
215
- // Continue with normal connection handling...
216
- }
217
- ```
218
-
219
- ### Socket Utility Integration
220
-
221
- When passing wrapped sockets to socket utility functions, the underlying socket must be extracted:
222
-
223
- ```typescript
224
- import { getUnderlyingSocket } from '../../core/models/socket-types.js';
225
-
226
- // In setupDirectConnection()
227
- const incomingSocket = getUnderlyingSocket(socket); // Extract raw socket
228
-
229
- setupBidirectionalForwarding(incomingSocket, targetSocket, {
230
- onClientData: (chunk) => {
231
- record.bytesReceived += chunk.length;
232
- },
233
- onServerData: (chunk) => {
234
- record.bytesSent += chunk.length;
235
- },
236
- onCleanup: (reason) => {
237
- this.connectionManager.cleanupConnection(record, reason);
238
- },
239
- enableHalfOpen: false // Required for proxy chains
240
- });
241
- ```
242
-
243
- ## Current Status and Limitations
244
-
245
- ### Implemented (v19.5.19+)
246
- - ✅ WrappedSocket foundation class
247
- - ✅ Socket wrapping in connection handler
248
- - ✅ Connection manager support for wrapped sockets
249
- - ✅ Socket utility integration helpers
250
- - ✅ Proxy IP configuration options
251
-
252
- ### Not Yet Implemented
253
- - ❌ PROXY protocol v1 header parsing
254
- - ❌ PROXY protocol v2 binary format support
255
- - ❌ Automatic PROXY protocol header generation when forwarding
256
- - ❌ HAProxy compatibility testing
257
- - ❌ AWS ELB/NLB compatibility testing
258
-
259
- ### Known Issues
260
- 1. **No actual PROXY protocol parsing** - The infrastructure is in place but the protocol parsing is not yet implemented
261
- 2. **Manual configuration required** - No automatic detection of PROXY protocol support
262
- 3. **Limited to TCP connections** - WebSocket connections through proxy chains may not preserve client IPs
263
-
264
- ## Testing Proxy Chains
265
-
266
- ### Basic Proxy Chain Test
267
-
268
- ```typescript
269
- // test/test.proxy-chain-simple.node.ts
270
- tap.test('simple proxy chain test', async () => {
271
- // Create backend server
272
- const backend = net.createServer((socket) => {
273
- console.log('Backend: Connection received');
274
- socket.write('HTTP/1.1 200 OK\r\n\r\nHello from backend');
275
- socket.end();
276
- });
277
-
278
- // Create inner proxy (downstream)
279
- const innerProxy = new SmartProxy({
280
- proxyIPs: ['127.0.0.1'], // Trust localhost for testing
281
- routes: [{
282
- name: 'to-backend',
283
- match: { ports: 8591 },
284
- action: {
285
- type: 'forward',
286
- target: { host: 'localhost', port: 9999 }
287
- }
288
- }]
289
- });
290
-
291
- // Create outer proxy (upstream)
292
- const outerProxy = new SmartProxy({
293
- sendProxyProtocol: true, // Send PROXY to inner
294
- routes: [{
295
- name: 'to-inner',
296
- match: { ports: 8590 },
297
- action: {
298
- type: 'forward',
299
- target: { host: 'localhost', port: 8591 }
300
- }
301
- }]
302
- });
303
-
304
- // Test connection through chain
305
- const client = net.connect(8590, 'localhost');
306
- client.write('GET / HTTP/1.1\r\nHost: test.com\r\n\r\n');
307
-
308
- // Verify no connection accumulation
309
- const counts = getConnectionCounts();
310
- expect(counts.proxy1).toEqual(0);
311
- expect(counts.proxy2).toEqual(0);
312
- });
313
- ```
314
-
315
- ## Best Practices
316
-
317
- ### 1. Always Configure Trusted Proxies
318
- ```typescript
319
- // Be specific about which IPs can send PROXY protocol
320
- proxyIPs: ['10.0.0.1', '10.0.0.2'], // Good
321
- proxyIPs: ['0.0.0.0/0'], // Bad - trusts everyone
322
- ```
323
-
324
- ### 2. Use CIDR Notation for Subnets
325
- ```typescript
326
- proxyIPs: [
327
- '10.0.0.0/24', // Trust entire subnet
328
- '192.168.1.5', // Trust specific IP
329
- '172.16.0.0/16' // Trust private network
330
- ]
331
- ```
332
-
333
- ### 3. Enable Half-Open Only When Needed
334
- ```typescript
335
- // For proxy chains, always disable half-open
336
- setupBidirectionalForwarding(client, server, {
337
- enableHalfOpen: false // Ensures proper cascade cleanup
338
- });
339
- ```
340
-
341
- ### 4. Monitor Connection Counts
342
- ```typescript
343
- // Regular monitoring prevents connection leaks
344
- setInterval(() => {
345
- const stats = proxy.getStatistics();
346
- console.log(`Active connections: ${stats.activeConnections}`);
347
- if (stats.activeConnections > 1000) {
348
- console.warn('High connection count detected');
349
- }
350
- }, 60000);
351
- ```
352
-
353
- ## Future Enhancements
354
-
355
- ### Phase 2: PROXY Protocol v1 Parser
356
- ```typescript
357
- // Planned implementation
358
- class ProxyProtocolParser {
359
- static parse(buffer: Buffer): ProxyInfo | null {
360
- // Parse "PROXY TCP4 <src-ip> <dst-ip> <src-port> <dst-port>\r\n"
361
- const header = buffer.toString('ascii', 0, 108);
362
- const match = header.match(/^PROXY (TCP4|TCP6) (\S+) (\S+) (\d+) (\d+)\r\n/);
363
- if (match) {
364
- return {
365
- protocol: match[1],
366
- sourceIP: match[2],
367
- destIP: match[3],
368
- sourcePort: parseInt(match[4]),
369
- destPort: parseInt(match[5]),
370
- headerLength: match[0].length
371
- };
372
- }
373
- return null;
374
- }
375
- }
376
- ```
377
-
378
- ### Phase 3: Automatic PROXY Protocol Detection
379
- - Peek at first bytes to detect PROXY protocol signature
380
- - Automatic fallback to direct connection if not present
381
- - Configurable timeout for protocol detection
382
-
383
- ### Phase 4: PROXY Protocol v2 Support
384
- - Binary protocol format for better performance
385
- - Additional metadata support (TLS info, ALPN, etc.)
386
- - AWS VPC endpoint ID preservation
387
-
388
- ## Troubleshooting
389
-
390
- ### Connection Accumulation in Proxy Chains
391
- If connections accumulate when chaining proxies:
392
- 1. Verify `enableHalfOpen: false` in socket forwarding
393
- 2. Check that both proxies have proper cleanup handlers
394
- 3. Monitor with connection count logging
395
- 4. Use `test.proxy-chain-simple.node.ts` as reference
396
-
397
- ### Real Client IP Not Preserved
398
- If the backend sees proxy IP instead of client IP:
399
- 1. Verify outer proxy has `sendProxyProtocol: true`
400
- 2. Verify inner proxy has outer proxy IP in `proxyIPs` list
401
- 3. Check logs for "Connection from trusted proxy" message
402
- 4. Ensure PROXY protocol parsing is implemented (currently pending)
403
-
404
- ### Performance Impact
405
- PROXY protocol adds minimal overhead:
406
- - One-time parsing cost per connection
407
- - Small memory overhead for real client info storage
408
- - No impact on data transfer performance
409
- - Negligible CPU impact for header generation
410
-
411
- ## Related Documentation
412
- - [Socket Utilities](./ts/core/utils/socket-utils.ts) - Low-level socket handling
413
- - [Connection Manager](./ts/proxies/smart-proxy/connection-manager.ts) - Connection lifecycle
414
- - [Route Handler](./ts/proxies/smart-proxy/route-connection-handler.ts) - Request routing
415
- - [Test Suite](./test/test.wrapped-socket.ts) - WrappedSocket unit tests