Compare commits

..

2 Commits

Author SHA1 Message Date
e9723a8af9 19.5.12
Some checks failed
Default (tags) / security (push) Failing after 16m15s
Default (tags) / test (push) Has been cancelled
Default (tags) / release (push) Has been cancelled
Default (tags) / metadata (push) Has been cancelled
2025-06-01 13:43:05 +00:00
300ab1a077 Fix connection leak in route-connection-handler by using safe socket creation
The previous fix only addressed ForwardingHandler classes but missed the critical setupDirectConnection() method in route-connection-handler.ts where SmartProxy actually handles connections. This caused active connections to rise indefinitely on ECONNREFUSED errors.

Changes:
- Import createSocketWithErrorHandler in route-connection-handler.ts
- Replace net.connect() with createSocketWithErrorHandler() in setupDirectConnection()
- Properly clean up connection records when server connection fails
- Add connectionFailed flag to prevent setup of failed connections

This ensures connection records are cleaned up immediately when backend connections fail, preventing memory leaks.
2025-06-01 13:42:46 +00:00
3 changed files with 56 additions and 9 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@push.rocks/smartproxy",
"version": "19.5.11",
"version": "19.5.12",
"private": false,
"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.",
"main": "dist_ts/index.js",

View File

@ -458,3 +458,10 @@ const socket = createSocketWithErrorHandler({
### Configuration
No configuration changes needed. The fix is transparent to users.
### Important Note
The fix was applied in two places:
1. **ForwardingHandler classes** (`https-passthrough-handler.ts`, etc.) - These are standalone forwarding utilities
2. **SmartProxy route-connection-handler** (`route-connection-handler.ts`) - This is where the actual SmartProxy connection handling happens
The critical fix for SmartProxy was in `setupDirectConnection()` method in route-connection-handler.ts, which now uses `createSocketWithErrorHandler()` to properly handle connection failures and clean up connection records.

View File

@ -9,7 +9,7 @@ import { TlsManager } from './tls-manager.js';
import { HttpProxyBridge } from './http-proxy-bridge.js';
import { TimeoutManager } from './timeout-manager.js';
import { RouteManager } from './route-manager.js';
import { cleanupSocket, createIndependentSocketHandlers, setupSocketHandlers } from '../../core/utils/socket-utils.js';
import { cleanupSocket, createIndependentSocketHandlers, setupSocketHandlers, createSocketWithErrorHandler } from '../../core/utils/socket-utils.js';
/**
* Handles new connection processing and setup logic with support for route-based configuration
@ -1073,13 +1073,52 @@ export class RouteConnectionHandler {
record.pendingDataSize = initialChunk.length;
}
// Create the target socket
const targetSocket = plugins.net.connect(connectionOptions);
record.outgoing = targetSocket;
record.outgoingStartTime = Date.now();
// Create the target socket with immediate error handling
let targetSocket: plugins.net.Socket;
// Apply socket optimizations
targetSocket.setNoDelay(this.settings.noDelay);
// Flag to track if initial connection failed
let connectionFailed = false;
targetSocket = createSocketWithErrorHandler({
port: finalTargetPort,
host: finalTargetHost,
onError: (error) => {
// Mark connection as failed
connectionFailed = true;
// Connection failed - clean up immediately
logger.log('error',
`Connection setup error for ${connectionId} to ${finalTargetHost}:${finalTargetPort}: ${error.message} (${(error as any).code})`,
{
connectionId,
targetHost: finalTargetHost,
targetPort: finalTargetPort,
errorMessage: error.message,
errorCode: (error as any).code,
component: 'route-handler'
}
);
// Resume the incoming socket to prevent it from hanging
socket.resume();
// Clean up the incoming socket
if (!socket.destroyed) {
socket.destroy();
}
// Clean up the connection record
this.connectionManager.initiateCleanupOnce(record, `connection_failed_${(error as any).code || 'unknown'}`);
}
});
// Only proceed with setup if connection didn't fail immediately
if (!connectionFailed) {
record.outgoing = targetSocket;
record.outgoingStartTime = Date.now();
// Apply socket optimizations
targetSocket.setNoDelay(this.settings.noDelay);
// Apply keep-alive settings if enabled
if (this.settings.keepAlive) {
@ -1346,5 +1385,6 @@ export class RouteConnectionHandler {
record.tlsHandshakeComplete = true;
}
});
} // End of if (!connectionFailed)
}
}