@push.rocks/smartproxy 19.5.20 → 19.5.21
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/dist_ts/core/utils/index.d.ts +1 -0
- package/dist_ts/core/utils/index.js +2 -1
- package/dist_ts/core/utils/proxy-protocol.d.ts +45 -0
- package/dist_ts/core/utils/proxy-protocol.js +201 -0
- package/dist_ts/proxies/smart-proxy/connection-manager.js +3 -1
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +1 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +1 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +108 -11
- package/package.json +1 -1
- package/readme.hints.md +8 -1
- package/readme.plan.md +23 -19
- package/readme.proxy-chain-summary.md +112 -0
- package/readme.proxy-protocol-example.md +462 -0
- package/readme.proxy-protocol.md +415 -0
- package/ts/core/utils/index.ts +1 -0
- package/ts/core/utils/proxy-protocol.ts +246 -0
- package/ts/proxies/smart-proxy/connection-manager.ts +2 -0
- package/ts/proxies/smart-proxy/models/interfaces.ts +1 -0
- package/ts/proxies/smart-proxy/models/route-types.ts +3 -0
- package/ts/proxies/smart-proxy/route-connection-handler.ts +115 -12
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
# SmartProxy PROXY Protocol Implementation Example
|
|
2
|
+
|
|
3
|
+
This document shows how PROXY protocol parsing could be implemented in SmartProxy. Note that this is a conceptual implementation guide - the actual parsing is not yet implemented in the current version.
|
|
4
|
+
|
|
5
|
+
## Conceptual PROXY Protocol v1 Parser Implementation
|
|
6
|
+
|
|
7
|
+
### Parser Class
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// This would go in ts/core/utils/proxy-protocol-parser.ts
|
|
11
|
+
import { logger } from './logger.js';
|
|
12
|
+
|
|
13
|
+
export interface IProxyProtocolInfo {
|
|
14
|
+
version: 1 | 2;
|
|
15
|
+
command: 'PROXY' | 'LOCAL';
|
|
16
|
+
family: 'TCP4' | 'TCP6' | 'UNKNOWN';
|
|
17
|
+
sourceIP: string;
|
|
18
|
+
destIP: string;
|
|
19
|
+
sourcePort: number;
|
|
20
|
+
destPort: number;
|
|
21
|
+
headerLength: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class ProxyProtocolParser {
|
|
25
|
+
private static readonly PROXY_V1_SIGNATURE = 'PROXY ';
|
|
26
|
+
private static readonly MAX_V1_HEADER_LENGTH = 108; // Max possible v1 header
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Parse PROXY protocol v1 header from buffer
|
|
30
|
+
* Returns null if not a valid PROXY protocol header
|
|
31
|
+
*/
|
|
32
|
+
static parseV1(buffer: Buffer): IProxyProtocolInfo | null {
|
|
33
|
+
// Need at least 8 bytes for "PROXY " + newline
|
|
34
|
+
if (buffer.length < 8) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check for v1 signature
|
|
39
|
+
const possibleHeader = buffer.toString('ascii', 0, 6);
|
|
40
|
+
if (possibleHeader !== this.PROXY_V1_SIGNATURE) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Find the end of the header (CRLF)
|
|
45
|
+
let headerEnd = -1;
|
|
46
|
+
for (let i = 6; i < Math.min(buffer.length, this.MAX_V1_HEADER_LENGTH); i++) {
|
|
47
|
+
if (buffer[i] === 0x0D && buffer[i + 1] === 0x0A) { // \r\n
|
|
48
|
+
headerEnd = i + 2;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (headerEnd === -1) {
|
|
54
|
+
// No complete header found
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Parse the header line
|
|
59
|
+
const headerLine = buffer.toString('ascii', 0, headerEnd - 2);
|
|
60
|
+
const parts = headerLine.split(' ');
|
|
61
|
+
|
|
62
|
+
if (parts.length !== 6) {
|
|
63
|
+
logger.log('warn', 'Invalid PROXY v1 header format', {
|
|
64
|
+
headerLine,
|
|
65
|
+
partCount: parts.length
|
|
66
|
+
});
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const [proxy, family, srcIP, dstIP, srcPort, dstPort] = parts;
|
|
71
|
+
|
|
72
|
+
// Validate family
|
|
73
|
+
if (!['TCP4', 'TCP6', 'UNKNOWN'].includes(family)) {
|
|
74
|
+
logger.log('warn', 'Invalid PROXY protocol family', { family });
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Validate ports
|
|
79
|
+
const sourcePort = parseInt(srcPort);
|
|
80
|
+
const destPort = parseInt(dstPort);
|
|
81
|
+
|
|
82
|
+
if (isNaN(sourcePort) || sourcePort < 1 || sourcePort > 65535 ||
|
|
83
|
+
isNaN(destPort) || destPort < 1 || destPort > 65535) {
|
|
84
|
+
logger.log('warn', 'Invalid PROXY protocol ports', { srcPort, dstPort });
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
version: 1,
|
|
90
|
+
command: 'PROXY',
|
|
91
|
+
family: family as 'TCP4' | 'TCP6' | 'UNKNOWN',
|
|
92
|
+
sourceIP: srcIP,
|
|
93
|
+
destIP: dstIP,
|
|
94
|
+
sourcePort,
|
|
95
|
+
destPort,
|
|
96
|
+
headerLength: headerEnd
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check if buffer potentially contains PROXY protocol
|
|
102
|
+
*/
|
|
103
|
+
static mightBeProxyProtocol(buffer: Buffer): boolean {
|
|
104
|
+
if (buffer.length < 6) return false;
|
|
105
|
+
|
|
106
|
+
// Check for v1 signature
|
|
107
|
+
const start = buffer.toString('ascii', 0, 6);
|
|
108
|
+
if (start === this.PROXY_V1_SIGNATURE) return true;
|
|
109
|
+
|
|
110
|
+
// Check for v2 signature (12 bytes: \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A)
|
|
111
|
+
if (buffer.length >= 12) {
|
|
112
|
+
const v2Sig = Buffer.from([0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A]);
|
|
113
|
+
if (buffer.compare(v2Sig, 0, 12, 0, 12) === 0) return true;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Integration with RouteConnectionHandler
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// This shows how it would be integrated into route-connection-handler.ts
|
|
125
|
+
|
|
126
|
+
private async handleProxyProtocol(
|
|
127
|
+
socket: plugins.net.Socket,
|
|
128
|
+
wrappedSocket: WrappedSocket,
|
|
129
|
+
record: IConnectionRecord
|
|
130
|
+
): Promise<Buffer | null> {
|
|
131
|
+
const remoteIP = socket.remoteAddress || '';
|
|
132
|
+
|
|
133
|
+
// Only parse PROXY protocol from trusted IPs
|
|
134
|
+
if (!this.settings.proxyIPs?.includes(remoteIP)) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return new Promise((resolve) => {
|
|
139
|
+
let buffer = Buffer.alloc(0);
|
|
140
|
+
let headerParsed = false;
|
|
141
|
+
|
|
142
|
+
const parseHandler = (chunk: Buffer) => {
|
|
143
|
+
// Accumulate data
|
|
144
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
145
|
+
|
|
146
|
+
// Try to parse PROXY protocol
|
|
147
|
+
const proxyInfo = ProxyProtocolParser.parseV1(buffer);
|
|
148
|
+
|
|
149
|
+
if (proxyInfo) {
|
|
150
|
+
// Update wrapped socket with real client info
|
|
151
|
+
wrappedSocket.setProxyInfo(proxyInfo.sourceIP, proxyInfo.sourcePort);
|
|
152
|
+
|
|
153
|
+
// Update connection record
|
|
154
|
+
record.remoteIP = proxyInfo.sourceIP;
|
|
155
|
+
|
|
156
|
+
logger.log('info', 'PROXY protocol parsed', {
|
|
157
|
+
connectionId: record.id,
|
|
158
|
+
realIP: proxyInfo.sourceIP,
|
|
159
|
+
realPort: proxyInfo.sourcePort,
|
|
160
|
+
proxyIP: remoteIP
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Remove this handler
|
|
164
|
+
socket.removeListener('data', parseHandler);
|
|
165
|
+
headerParsed = true;
|
|
166
|
+
|
|
167
|
+
// Return remaining data after header
|
|
168
|
+
const remaining = buffer.slice(proxyInfo.headerLength);
|
|
169
|
+
resolve(remaining.length > 0 ? remaining : null);
|
|
170
|
+
} else if (buffer.length > 108) {
|
|
171
|
+
// Max v1 header length exceeded, not PROXY protocol
|
|
172
|
+
socket.removeListener('data', parseHandler);
|
|
173
|
+
headerParsed = true;
|
|
174
|
+
resolve(buffer);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Set timeout for PROXY protocol parsing
|
|
179
|
+
const timeout = setTimeout(() => {
|
|
180
|
+
if (!headerParsed) {
|
|
181
|
+
socket.removeListener('data', parseHandler);
|
|
182
|
+
logger.log('warn', 'PROXY protocol parsing timeout', {
|
|
183
|
+
connectionId: record.id,
|
|
184
|
+
bufferLength: buffer.length
|
|
185
|
+
});
|
|
186
|
+
resolve(buffer.length > 0 ? buffer : null);
|
|
187
|
+
}
|
|
188
|
+
}, 1000); // 1 second timeout
|
|
189
|
+
|
|
190
|
+
socket.on('data', parseHandler);
|
|
191
|
+
|
|
192
|
+
// Clean up on early close
|
|
193
|
+
socket.once('close', () => {
|
|
194
|
+
clearTimeout(timeout);
|
|
195
|
+
if (!headerParsed) {
|
|
196
|
+
socket.removeListener('data', parseHandler);
|
|
197
|
+
resolve(null);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Modified handleConnection to include PROXY protocol parsing
|
|
204
|
+
public async handleConnection(socket: plugins.net.Socket): void {
|
|
205
|
+
const remoteIP = socket.remoteAddress || '';
|
|
206
|
+
const localPort = socket.localPort || 0;
|
|
207
|
+
|
|
208
|
+
// Always wrap the socket
|
|
209
|
+
const wrappedSocket = new WrappedSocket(socket);
|
|
210
|
+
|
|
211
|
+
// Create connection record
|
|
212
|
+
const record = this.connectionManager.createConnection(wrappedSocket);
|
|
213
|
+
if (!record) return;
|
|
214
|
+
|
|
215
|
+
// If from trusted proxy, parse PROXY protocol
|
|
216
|
+
if (this.settings.proxyIPs?.includes(remoteIP)) {
|
|
217
|
+
const remainingData = await this.handleProxyProtocol(socket, wrappedSocket, record);
|
|
218
|
+
|
|
219
|
+
if (remainingData) {
|
|
220
|
+
// Process remaining data as normal
|
|
221
|
+
this.handleInitialData(wrappedSocket, record, remainingData);
|
|
222
|
+
} else {
|
|
223
|
+
// Wait for more data
|
|
224
|
+
this.handleInitialData(wrappedSocket, record);
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
// Not from trusted proxy, handle normally
|
|
228
|
+
this.handleInitialData(wrappedSocket, record);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Sending PROXY Protocol When Forwarding
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
// This would be added to setupDirectConnection method
|
|
237
|
+
|
|
238
|
+
private setupDirectConnection(
|
|
239
|
+
socket: plugins.net.Socket | WrappedSocket,
|
|
240
|
+
record: IConnectionRecord,
|
|
241
|
+
serverName?: string,
|
|
242
|
+
initialChunk?: Buffer,
|
|
243
|
+
overridePort?: number,
|
|
244
|
+
targetHost?: string,
|
|
245
|
+
targetPort?: number
|
|
246
|
+
): void {
|
|
247
|
+
// ... existing code ...
|
|
248
|
+
|
|
249
|
+
// Create target socket
|
|
250
|
+
const targetSocket = createSocketWithErrorHandler({
|
|
251
|
+
port: finalTargetPort,
|
|
252
|
+
host: finalTargetHost,
|
|
253
|
+
onConnect: () => {
|
|
254
|
+
// If sendProxyProtocol is enabled, send PROXY header first
|
|
255
|
+
if (this.settings.sendProxyProtocol) {
|
|
256
|
+
const proxyHeader = this.buildProxyProtocolHeader(wrappedSocket, targetSocket);
|
|
257
|
+
targetSocket.write(proxyHeader);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Then send any pending data
|
|
261
|
+
if (record.pendingData.length > 0) {
|
|
262
|
+
const combinedData = Buffer.concat(record.pendingData);
|
|
263
|
+
targetSocket.write(combinedData);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ... rest of connection setup ...
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private buildProxyProtocolHeader(
|
|
272
|
+
clientSocket: WrappedSocket,
|
|
273
|
+
serverSocket: net.Socket
|
|
274
|
+
): Buffer {
|
|
275
|
+
const family = clientSocket.remoteFamily === 'IPv6' ? 'TCP6' : 'TCP4';
|
|
276
|
+
const srcIP = clientSocket.remoteAddress || '0.0.0.0';
|
|
277
|
+
const srcPort = clientSocket.remotePort || 0;
|
|
278
|
+
const dstIP = serverSocket.localAddress || '0.0.0.0';
|
|
279
|
+
const dstPort = serverSocket.localPort || 0;
|
|
280
|
+
|
|
281
|
+
const header = `PROXY ${family} ${srcIP} ${dstIP} ${srcPort} ${dstPort}\r\n`;
|
|
282
|
+
return Buffer.from(header, 'ascii');
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Complete Example: HAProxy Compatible Setup
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
// Example showing a complete HAProxy-compatible SmartProxy setup
|
|
290
|
+
|
|
291
|
+
import { SmartProxy } from '@push.rocks/smartproxy';
|
|
292
|
+
|
|
293
|
+
// Configuration matching HAProxy's proxy protocol behavior
|
|
294
|
+
const proxy = new SmartProxy({
|
|
295
|
+
// Accept PROXY protocol from these sources (like HAProxy's 'accept-proxy')
|
|
296
|
+
proxyIPs: [
|
|
297
|
+
'10.0.0.0/8', // Private network load balancers
|
|
298
|
+
'172.16.0.0/12', // Docker networks
|
|
299
|
+
'192.168.0.0/16' // Local networks
|
|
300
|
+
],
|
|
301
|
+
|
|
302
|
+
// Send PROXY protocol to backends (like HAProxy's 'send-proxy')
|
|
303
|
+
sendProxyProtocol: true,
|
|
304
|
+
|
|
305
|
+
routes: [
|
|
306
|
+
{
|
|
307
|
+
name: 'web-app',
|
|
308
|
+
match: {
|
|
309
|
+
ports: 443,
|
|
310
|
+
domains: ['app.example.com', 'www.example.com']
|
|
311
|
+
},
|
|
312
|
+
action: {
|
|
313
|
+
type: 'forward',
|
|
314
|
+
target: {
|
|
315
|
+
host: 'backend-pool.internal',
|
|
316
|
+
port: 8080
|
|
317
|
+
},
|
|
318
|
+
tls: {
|
|
319
|
+
mode: 'terminate',
|
|
320
|
+
certificate: 'auto',
|
|
321
|
+
acme: {
|
|
322
|
+
email: 'ssl@example.com'
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
]
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// Start the proxy
|
|
331
|
+
await proxy.start();
|
|
332
|
+
|
|
333
|
+
// The proxy will now:
|
|
334
|
+
// 1. Accept connections on port 443
|
|
335
|
+
// 2. Parse PROXY protocol from trusted IPs
|
|
336
|
+
// 3. Terminate TLS
|
|
337
|
+
// 4. Forward to backend with PROXY protocol header
|
|
338
|
+
// 5. Backend sees real client IP
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Testing PROXY Protocol
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
// Test client that sends PROXY protocol
|
|
345
|
+
import * as net from 'net';
|
|
346
|
+
|
|
347
|
+
function createProxyProtocolClient(
|
|
348
|
+
realClientIP: string,
|
|
349
|
+
realClientPort: number,
|
|
350
|
+
proxyHost: string,
|
|
351
|
+
proxyPort: number
|
|
352
|
+
): net.Socket {
|
|
353
|
+
const client = net.connect(proxyPort, proxyHost);
|
|
354
|
+
|
|
355
|
+
client.on('connect', () => {
|
|
356
|
+
// Send PROXY protocol header
|
|
357
|
+
const header = `PROXY TCP4 ${realClientIP} ${proxyHost} ${realClientPort} ${proxyPort}\r\n`;
|
|
358
|
+
client.write(header);
|
|
359
|
+
|
|
360
|
+
// Then send actual request
|
|
361
|
+
client.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
return client;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Usage
|
|
368
|
+
const client = createProxyProtocolClient(
|
|
369
|
+
'203.0.113.45', // Real client IP
|
|
370
|
+
54321, // Real client port
|
|
371
|
+
'localhost', // Proxy host
|
|
372
|
+
8080 // Proxy port
|
|
373
|
+
);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## AWS Network Load Balancer Example
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
// Configuration for AWS NLB with PROXY protocol v2
|
|
380
|
+
const proxy = new SmartProxy({
|
|
381
|
+
// AWS NLB IP ranges (get current list from AWS)
|
|
382
|
+
proxyIPs: [
|
|
383
|
+
'10.0.0.0/8', // VPC CIDR
|
|
384
|
+
// Add specific NLB IPs or use AWS IP ranges
|
|
385
|
+
],
|
|
386
|
+
|
|
387
|
+
// AWS NLB uses PROXY protocol v2 by default
|
|
388
|
+
acceptProxyProtocolV2: true, // Future feature
|
|
389
|
+
|
|
390
|
+
routes: [{
|
|
391
|
+
name: 'aws-app',
|
|
392
|
+
match: { ports: 443 },
|
|
393
|
+
action: {
|
|
394
|
+
type: 'forward',
|
|
395
|
+
target: {
|
|
396
|
+
host: 'app-cluster.internal',
|
|
397
|
+
port: 8443
|
|
398
|
+
},
|
|
399
|
+
tls: { mode: 'passthrough' }
|
|
400
|
+
}
|
|
401
|
+
}]
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// The proxy will:
|
|
405
|
+
// 1. Accept PROXY protocol v2 from AWS NLB
|
|
406
|
+
// 2. Preserve VPC endpoint IDs and other metadata
|
|
407
|
+
// 3. Forward to backend with real client information
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Debugging PROXY Protocol
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
// Enable detailed logging to debug PROXY protocol parsing
|
|
414
|
+
const proxy = new SmartProxy({
|
|
415
|
+
enableDetailedLogging: true,
|
|
416
|
+
proxyIPs: ['10.0.0.1'],
|
|
417
|
+
|
|
418
|
+
// Add custom logging for debugging
|
|
419
|
+
routes: [{
|
|
420
|
+
name: 'debug-route',
|
|
421
|
+
match: { ports: 8080 },
|
|
422
|
+
action: {
|
|
423
|
+
type: 'socket-handler',
|
|
424
|
+
socketHandler: async (socket, context) => {
|
|
425
|
+
console.log('Socket handler called with context:', {
|
|
426
|
+
clientIp: context.clientIp, // Real IP from PROXY protocol
|
|
427
|
+
port: context.port,
|
|
428
|
+
connectionId: context.connectionId,
|
|
429
|
+
timestamp: context.timestamp
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// Handle the socket...
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}]
|
|
436
|
+
});
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
## Security Considerations
|
|
440
|
+
|
|
441
|
+
1. **Always validate trusted proxy IPs** - Never accept PROXY protocol from untrusted sources
|
|
442
|
+
2. **Use specific IP ranges** - Avoid wildcards like `0.0.0.0/0`
|
|
443
|
+
3. **Implement rate limiting** - PROXY protocol parsing has a computational cost
|
|
444
|
+
4. **Validate header format** - Reject malformed headers immediately
|
|
445
|
+
5. **Set parsing timeouts** - Prevent slow loris attacks via PROXY headers
|
|
446
|
+
6. **Log parsing failures** - Monitor for potential attacks or misconfigurations
|
|
447
|
+
|
|
448
|
+
## Performance Considerations
|
|
449
|
+
|
|
450
|
+
1. **Header parsing overhead** - Minimal, one-time cost per connection
|
|
451
|
+
2. **Memory usage** - Small buffer for header accumulation (max 108 bytes for v1)
|
|
452
|
+
3. **Connection establishment** - Slight delay for PROXY protocol parsing
|
|
453
|
+
4. **Throughput impact** - None after initial header parsing
|
|
454
|
+
5. **CPU usage** - Negligible for well-formed headers
|
|
455
|
+
|
|
456
|
+
## Future Enhancements
|
|
457
|
+
|
|
458
|
+
1. **PROXY Protocol v2** - Binary format for better performance
|
|
459
|
+
2. **TLS information preservation** - Pass TLS version, cipher, SNI via PP2
|
|
460
|
+
3. **Custom type-length-value (TLV) fields** - Extended metadata support
|
|
461
|
+
4. **Connection pooling** - Reuse backend connections with different client IPs
|
|
462
|
+
5. **Health checks** - Skip PROXY protocol for health check connections
|