Compare commits

...

24 Commits

Author SHA1 Message Date
2b69150545 3.32.2
Some checks failed
Default (tags) / security (push) Successful in 35s
Default (tags) / test (push) Failing after 1m2s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 09:12:40 +00:00
85cc57ae10 fix(PortProxy): Simplify TLS handshake SNI extraction and update timeout settings in PortProxy for improved maintainability and reliability. 2025-03-11 09:12:40 +00:00
e021b66898 3.32.1
Some checks failed
Default (tags) / security (push) Successful in 30s
Default (tags) / test (push) Failing after 1m3s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 04:39:17 +00:00
865d21b36a fix(portproxy): Relax TLS handshake and connection timeout settings for improved stability in chained proxy scenarios; update TLS session cache defaults and add keep-alive flags to connection records. 2025-03-11 04:39:17 +00:00
58ba0d9362 3.32.0
Some checks failed
Default (tags) / security (push) Successful in 34s
Default (tags) / test (push) Failing after 1m2s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 04:24:29 +00:00
ccccc5b8c8 feat(PortProxy): Enhance TLS session cache, SNI extraction, and chained proxy support in PortProxy. Improve handling of multiple and fragmented TLS records, and add new configuration options (isChainedProxy, chainPosition, aggressiveTlsRefresh, tlsSessionCache) for robust TLS certificate refresh. 2025-03-11 04:24:29 +00:00
d8466a866c 3.31.2
Some checks failed
Default (tags) / security (push) Successful in 28s
Default (tags) / test (push) Failing after 1m3s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 03:56:09 +00:00
119b643690 fix(PortProxy): Improve SNI renegotiation handling by adding flexible domain configuration matching on rehandshake and session resumption events. 2025-03-11 03:56:09 +00:00
98f1e0df4c 3.31.1
Some checks failed
Default (tags) / security (push) Successful in 37s
Default (tags) / test (push) Failing after 1m3s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 03:48:10 +00:00
d6022c8f8a fix(PortProxy): Improve TLS handshake buffering and enhance debug logging for SNI forwarding in PortProxy 2025-03-11 03:48:10 +00:00
0ea0f02428 fix(PortProxy): Improve connection reliability for initial and resumed TLS sessions
Added enhanced connection handling to fix issues with both initial connections and TLS session resumption:

1. Improved debugging for connection setup with detailed logging
2. Added explicit timeout for backend connections to prevent hanging connections
3. Enhanced error recovery for connection failures with faster client notification
4. Added detailed session tracking to maintain domain context across TLS sessions
5. Fixed handling of TLS renegotiation with improved activity timestamp updates

This should address the issue where initial connections may fail but subsequent retries succeed,
as well as ensuring proper certificate selection for resumed TLS sessions.

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-11 03:33:03 +00:00
e452f55203 3.31.0
Some checks failed
Default (tags) / security (push) Successful in 35s
Default (tags) / test (push) Failing after 1m4s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 03:16:04 +00:00
55f25f1976 feat(PortProxy): Improve TLS handshake SNI extraction and add session resumption tracking in PortProxy 2025-03-11 03:16:04 +00:00
98b7f3ed7f 3.30.8
Some checks failed
Default (tags) / security (push) Failing after 11m56s
Default (tags) / test (push) Has been cancelled
Default (tags) / release (push) Has been cancelled
Default (tags) / metadata (push) Has been cancelled
2025-03-11 02:50:01 +00:00
cb83caeafd fix(core): No changes in this commit. 2025-03-11 02:50:01 +00:00
7850a80452 fix(PortProxy): Fix TypeScript errors by using correct variable names
Fixed TypeScript errors caused by using 'connectionRecord' instead of 'record' in TLS renegotiation handlers.
The variable name mistake occurred when moving and restructuring the TLS handshake detection code.

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-11 02:47:57 +00:00
ef8f583a90 fix(PortProxy): Move TLS renegotiation detection before socket piping
Fundamentally restructured TLS renegotiation handling to ensure handshake packets are properly detected. The previous implementation attached event handlers after pipe() was established, which might have caused handshake packets to bypass detection. Key changes:

1. Moved renegotiation detection before pipe() to ensure all TLS handshake packets are detected
2. Added explicit lockedDomain setting for all SNI connections
3. Simplified the NetworkProxy TLS handshake detection
4. Removed redundant data handlers that could interfere with each other

These changes should make renegotiation detection more reliable regardless of how Node.js internal pipe() implementation handles data events.

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-11 02:45:51 +00:00
2bdd6f8c1f fix(PortProxy): Update activity timestamp during TLS renegotiation to prevent connection timeouts
Ensures that TLS renegotiation packets properly update the connection's activity timestamp even when no SNI is present or when there are errors processing the renegotiation. This prevents connections from being closed due to inactivity during legitimate TLS renegotiation.

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-11 02:40:08 +00:00
99d28eafd1 3.30.7
Some checks failed
Default (tags) / security (push) Successful in 29s
Default (tags) / test (push) Failing after 1m1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 02:25:59 +00:00
788b444fcc fix(PortProxy): Improve TLS renegotiation SNI handling by first checking if the new SNI is allowed under the existing domain config. If not, attempt to find an alternative domain config and update the locked domain accordingly; otherwise, terminate the connection on SNI mismatch. 2025-03-11 02:25:58 +00:00
4225abe3c4 3.30.6
Some checks failed
Default (tags) / security (push) Successful in 36s
Default (tags) / test (push) Failing after 1m0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 02:18:56 +00:00
74fdb58f84 fix(PortProxy): Improve TLS renegotiation handling in PortProxy by validating the new SNI against allowed domain configurations. If the new SNI is permitted based on existing IP rules, update the locked domain to allow connection reuse; otherwise, terminate the connection to prevent misrouting. 2025-03-11 02:18:56 +00:00
bffdaffe39 3.30.5
Some checks failed
Default (tags) / security (push) Successful in 20s
Default (tags) / test (push) Failing after 1m1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-10 22:36:28 +00:00
67a4228518 fix(internal): No uncommitted changes detected; project files and tests remain unchanged. 2025-03-10 22:36:28 +00:00
4 changed files with 226 additions and 455 deletions

View File

@ -1,5 +1,78 @@
# Changelog
## 2025-03-11 - 3.32.2 - fix(PortProxy)
Simplify TLS handshake SNI extraction and update timeout settings in PortProxy for improved maintainability and reliability.
- Removed legacy and deprecated fields related to chained proxy configurations (isChainedProxy, chainPosition, aggressiveTlsRefresh).
- Refactored the extractSNI functions to use a simpler, more robust approach for TLS ClientHello processing.
- Adjusted default timeout and keep-alive settings to more standard values (e.g. initialDataTimeout set to 60s, socketTimeout to 1h).
- Eliminated redundant TLS session cache and deep TLS refresh logic.
- Improved logging and error handling during connection setup and renegotiation phases.
## 2025-03-11 - 3.32.1 - fix(portproxy)
Relax TLS handshake and connection timeout settings for improved stability in chained proxy scenarios; update TLS session cache defaults and add keep-alive flags to connection records.
- Increased TLS session cache maximum entries from 10,000 to 20,000, expiry time from 24 hours to 7 days, and cleanup interval from 10 minutes to 30 minutes
- Relaxed socket timeouts: standalone connections now use up to 6 hours, with chained proxies adjusted for 56 hours based on proxy position
- Updated inactivity, connection, and initial handshake timeouts to provide a more relaxed behavior under high-traffic chained proxy scenarios
- Increased keepAliveInitialDelay from 10 seconds to 30 seconds and introduced separate incoming and outgoing keep-alive flags
- Enhanced TLS renegotiation handling with more detailed logging and temporary processing flags to avoid duplicate processing
- Updated NetworkProxy integration to use optimized connection settings and more aggressive application-level keep-alive probes
## 2025-03-11 - 3.32.0 - feat(PortProxy)
Enhance TLS session cache, SNI extraction, and chained proxy support in PortProxy. Improve handling of multiple and fragmented TLS records, and add new configuration options (isChainedProxy, chainPosition, aggressiveTlsRefresh, tlsSessionCache) for robust TLS certificate refresh.
- Implement TlsSessionCache with configurable cleanup, eviction, and statistics.
- Improve extractSNIInfo to process multiple TLS records and partial handshake data.
- Add new settings to detect chained proxy scenarios and adjust timeouts accordingly.
- Enhance TLS state refresh with aggressive probing and deep refresh sequence.
## 2025-03-11 - 3.31.2 - fix(PortProxy)
Improve SNI renegotiation handling by adding flexible domain configuration matching on rehandshake and session resumption events.
- When a rehandshake is detected with a changed SNI, first check existing domain config rules and log if allowed.
- If the exact domain config is not found, additionally attempt flexible matching using parent domain and wildcard patterns.
- For resumed sessions, try an exact match first and then use fallback logic to select a similar domain config based on matching target IP.
- Enhanced logging added to help diagnose missing or mismatched domain configurations.
## 2025-03-11 - 3.31.1 - fix(PortProxy)
Improve TLS handshake buffering and enhance debug logging for SNI forwarding in PortProxy
- Explicitly copy the initial TLS handshake data to prevent mutation before buffering
- Log buffered TLS handshake data with SNI information for better diagnostics
- Add detailed error logs on TLS connection failures, including server and domain config status
- Output additional debug messages during ClientHello forwarding to verify proper TLS handshake processing
## 2025-03-11 - 3.31.0 - feat(PortProxy)
Improve TLS handshake SNI extraction and add session resumption tracking in PortProxy
- Added ITlsSessionInfo interface and a global tlsSessionCache to track TLS session IDs for session resumption
- Implemented a cleanup timer for the TLS session cache with startSessionCleanupTimer and stopSessionCleanupTimer
- Enhanced extractSNIInfo to return detailed SNI information including session IDs, ticket details, and resumption status
- Updated renegotiation handlers to use extractSNIInfo for proper SNI extraction during TLS rehandshake
## 2025-03-11 - 3.30.8 - fix(core)
No changes in this commit.
## 2025-03-11 - 3.30.7 - fix(PortProxy)
Improve TLS renegotiation SNI handling by first checking if the new SNI is allowed under the existing domain config. If not, attempt to find an alternative domain config and update the locked domain accordingly; otherwise, terminate the connection on SNI mismatch.
- Added a preliminary check against the original domain config to allow re-handshakes if the new SNI matches allowed patterns.
- If the original config does not allow, search for an alternative domain config and validate IP rules.
- Update the locked domain when allowed, ensuring connection reuse with valid certificate context.
- Terminate the connection if no suitable domain config is found or IP restrictions are violated.
## 2025-03-11 - 3.30.6 - fix(PortProxy)
Improve TLS renegotiation handling in PortProxy by validating the new SNI against allowed domain configurations. If the new SNI is permitted based on existing IP rules, update the locked domain to allow connection reuse; otherwise, terminate the connection to prevent misrouting.
- Added logic to check if a new SNI during renegotiation is allowed by comparing IP rules from the matching domain configuration.
- Updated detailed logging to indicate when a valid SNI change is accepted and when it results in a mismatch termination.
## 2025-03-10 - 3.30.5 - fix(internal)
No uncommitted changes detected; project files and tests remain unchanged.
## 2025-03-10 - 3.30.4 - fix(PortProxy)
Fix TLS renegotiation handling and adjust TLS keep-alive timeouts in PortProxy implementation

View File

@ -1,6 +1,6 @@
{
"name": "@push.rocks/smartproxy",
"version": "3.30.4",
"version": "3.32.2",
"private": false,
"description": "A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, and dynamic routing with authentication options.",
"main": "dist_ts/index.js",

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartproxy',
version: '3.30.4',
version: '3.32.2',
description: 'A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, and dynamic routing with authentication options.'
}

View File

@ -10,18 +10,13 @@ export interface IDomainConfig {
portRanges?: Array<{ from: number; to: number }>; // Optional port ranges
// Allow domain-specific timeout override
connectionTimeout?: number; // Connection timeout override (ms)
// New properties for NetworkProxy integration
useNetworkProxy?: boolean; // When true, forwards TLS connections to NetworkProxy
networkProxyIndex?: number; // Optional index to specify which NetworkProxy to use (defaults to 0)
}
/**
* Port proxy settings including global allowed port ranges
*
* NOTE: In version 3.31.0+, timeout settings have been simplified and hardcoded with sensible defaults
* to ensure TLS certificate safety in all deployment scenarios, especially chained proxies.
*/
/** Port proxy settings including global allowed port ranges */
export interface IPortProxySettings extends plugins.tls.TlsOptions {
fromPort: number;
toPort: number;
@ -32,10 +27,14 @@ export interface IPortProxySettings extends plugins.tls.TlsOptions {
defaultBlockedIPs?: string[];
preserveSourceIP?: boolean;
// Simplified timeout settings
// Timeout settings
initialDataTimeout?: number; // Timeout for initial data/SNI (ms), default: 60000 (60s)
socketTimeout?: number; // Socket inactivity timeout (ms), default: 3600000 (1h)
inactivityCheckInterval?: number; // How often to check for inactive connections (ms), default: 60000 (60s)
maxConnectionLifetime?: number; // Default max connection lifetime (ms), default: 86400000 (24h)
inactivityTimeout?: number; // Inactivity timeout (ms), default: 14400000 (4h)
gracefulShutdownTimeout?: number; // (ms) maximum time to wait for connections to close during shutdown
// Ranged port settings
globalPortRanges: Array<{ from: number; to: number }>; // Global allowed port ranges
forwardAllGlobalRanges?: boolean; // When true, forwards all connections on global port ranges to the global targetIP
@ -45,7 +44,9 @@ export interface IPortProxySettings extends plugins.tls.TlsOptions {
keepAliveInitialDelay?: number; // Initial delay before sending keepalive probes (ms)
maxPendingDataSize?: number; // Maximum bytes to buffer during connection setup
// Logging settings
// Enhanced features
disableInactivityCheck?: boolean; // Disable inactivity checking entirely
enableKeepAliveProbes?: boolean; // Enable TCP keep-alive probes
enableDetailedLogging?: boolean; // Enable detailed connection logging
enableTlsDebugLogging?: boolean; // Enable TLS handshake debug logging
enableRandomizedTimeouts?: boolean; // Randomize timeouts slightly to prevent thundering herd
@ -53,8 +54,13 @@ export interface IPortProxySettings extends plugins.tls.TlsOptions {
// Rate limiting and security
maxConnectionsPerIP?: number; // Maximum simultaneous connections from a single IP
connectionRateLimitPerMinute?: number; // Max new connections per minute from a single IP
// NetworkProxy integration
// Enhanced keep-alive settings
keepAliveTreatment?: 'standard' | 'extended' | 'immortal'; // How to treat keep-alive connections
keepAliveInactivityMultiplier?: number; // Multiplier for inactivity timeout for keep-alive connections
extendedKeepAliveLifetime?: number; // Extended lifetime for keep-alive connections (ms)
// New property for NetworkProxy integration
networkProxies?: NetworkProxy[]; // Array of NetworkProxy instances to use for TLS termination
}
@ -84,20 +90,16 @@ interface IConnectionRecord {
tlsHandshakeComplete: boolean; // Whether the TLS handshake is complete
hasReceivedInitialData: boolean; // Whether initial data has been received
domainConfig?: IDomainConfig; // Associated domain config for this connection
// Keep-alive tracking
hasKeepAlive: boolean; // Whether keep-alive is enabled for this connection
inactivityWarningIssued?: boolean; // Whether an inactivity warning has been issued
incomingTerminationReason?: string | null; // Reason for incoming termination
outgoingTerminationReason?: string | null; // Reason for outgoing termination
// New field for NetworkProxy tracking
usingNetworkProxy?: boolean; // Whether this connection is using a NetworkProxy
networkProxyIndex?: number; // Which NetworkProxy instance is being used
// Sleep detection fields
possibleSystemSleep?: boolean; // Flag to indicate a possible system sleep was detected
lastSleepDetection?: number; // Timestamp of the last sleep detection
}
/**
@ -326,22 +328,7 @@ const randomizeTimeout = (baseTimeout: number, variationPercent: number = 5): nu
export class PortProxy {
private netServers: plugins.net.Server[] = [];
// Define the internal settings interface to include all fields, including those removed from the public interface
settings: IPortProxySettings & {
// Internal fields removed from public interface in 3.31.0+
initialDataTimeout: number;
socketTimeout: number;
inactivityCheckInterval: number;
maxConnectionLifetime: number;
inactivityTimeout: number;
disableInactivityCheck: boolean;
enableKeepAliveProbes: boolean;
keepAliveTreatment: 'standard' | 'extended' | 'immortal';
keepAliveInactivityMultiplier: number;
extendedKeepAliveLifetime: number;
};
settings: IPortProxySettings;
private connectionRecords: Map<string, IConnectionRecord> = new Map();
private connectionLogger: NodeJS.Timeout | null = null;
private isShuttingDown: boolean = false;
@ -361,48 +348,49 @@ export class PortProxy {
// Connection tracking by IP for rate limiting
private connectionsByIP: Map<string, Set<string>> = new Map();
private connectionRateByIP: Map<string, number[]> = new Map();
// New property to store NetworkProxy instances
private networkProxies: NetworkProxy[] = [];
constructor(settingsArg: IPortProxySettings) {
// Set hardcoded sensible defaults for all settings
// Set reasonable defaults for all settings
this.settings = {
...settingsArg,
targetIP: settingsArg.targetIP || 'localhost',
// Hardcoded timeout settings optimized for TLS safety in all deployment scenarios
initialDataTimeout: 60000, // 60 seconds for initial handshake
socketTimeout: 1800000, // 30 minutes - short enough for regular certificate refresh
inactivityCheckInterval: 60000, // 60 seconds interval for regular cleanup
maxConnectionLifetime: 3600000, // 1 hour maximum lifetime for all connections
inactivityTimeout: 1800000, // 30 minutes inactivity timeout
// Timeout settings with reasonable defaults
initialDataTimeout: settingsArg.initialDataTimeout || 60000, // 60 seconds for initial handshake
socketTimeout: ensureSafeTimeout(settingsArg.socketTimeout || 3600000), // 1 hour socket timeout
inactivityCheckInterval: settingsArg.inactivityCheckInterval || 60000, // 60 seconds interval
maxConnectionLifetime: ensureSafeTimeout(settingsArg.maxConnectionLifetime || 86400000), // 24 hours default
inactivityTimeout: ensureSafeTimeout(settingsArg.inactivityTimeout || 14400000), // 4 hours inactivity timeout
gracefulShutdownTimeout: settingsArg.gracefulShutdownTimeout || 30000, // 30 seconds
// Socket optimization settings
noDelay: settingsArg.noDelay !== undefined ? settingsArg.noDelay : true,
keepAlive: settingsArg.keepAlive !== undefined ? settingsArg.keepAlive : true,
keepAliveInitialDelay: settingsArg.keepAliveInitialDelay || 10000, // 10 seconds
keepAliveInitialDelay: settingsArg.keepAliveInitialDelay || 10000, // 10 seconds (reduced for responsiveness)
maxPendingDataSize: settingsArg.maxPendingDataSize || 10 * 1024 * 1024, // 10MB to handle large TLS handshakes
// Feature flags - simplified with sensible defaults
disableInactivityCheck: false, // Always enable inactivity checks for TLS safety
enableKeepAliveProbes: true, // Always enable keep-alive probes for connection health
// Feature flags
disableInactivityCheck: settingsArg.disableInactivityCheck || false,
enableKeepAliveProbes: settingsArg.enableKeepAliveProbes !== undefined
? settingsArg.enableKeepAliveProbes : true, // Enable by default
enableDetailedLogging: settingsArg.enableDetailedLogging || false,
enableTlsDebugLogging: settingsArg.enableTlsDebugLogging || false,
enableRandomizedTimeouts: settingsArg.enableRandomizedTimeouts || false,
enableRandomizedTimeouts: settingsArg.enableRandomizedTimeouts || false, // Disable randomization by default
// Rate limiting defaults
maxConnectionsPerIP: settingsArg.maxConnectionsPerIP || 100, // 100 connections per IP
connectionRateLimitPerMinute: settingsArg.connectionRateLimitPerMinute || 300, // 300 per minute
// Keep-alive settings with sensible defaults that ensure certificate safety
keepAliveTreatment: 'standard', // Always use standard treatment for certificate safety
keepAliveInactivityMultiplier: 2, // 2x normal inactivity timeout for minimal extension
extendedKeepAliveLifetime: 3 * 60 * 60 * 1000, // 3 hours maximum (previously was 7 days!)
// Enhanced keep-alive settings
keepAliveTreatment: settingsArg.keepAliveTreatment || 'extended', // Extended by default
keepAliveInactivityMultiplier: settingsArg.keepAliveInactivityMultiplier || 6, // 6x normal inactivity timeout
extendedKeepAliveLifetime: settingsArg.extendedKeepAliveLifetime || 7 * 24 * 60 * 60 * 1000, // 7 days
};
// Store NetworkProxy instances if provided
this.networkProxies = settingsArg.networkProxies || [];
}
@ -425,66 +413,58 @@ export class PortProxy {
serverName?: string
): void {
// Determine which NetworkProxy to use
const proxyIndex =
domainConfig.networkProxyIndex !== undefined ? domainConfig.networkProxyIndex : 0;
const proxyIndex = domainConfig.networkProxyIndex !== undefined
? domainConfig.networkProxyIndex
: 0;
// Validate the NetworkProxy index
if (proxyIndex < 0 || proxyIndex >= this.networkProxies.length) {
console.log(
`[${connectionId}] Invalid NetworkProxy index: ${proxyIndex}. Using fallback direct connection.`
);
console.log(`[${connectionId}] Invalid NetworkProxy index: ${proxyIndex}. Using fallback direct connection.`);
// Fall back to direct connection
return this.setupDirectConnection(
connectionId,
socket,
record,
domainConfig,
serverName,
initialData
);
return this.setupDirectConnection(connectionId, socket, record, domainConfig, serverName, initialData);
}
const networkProxy = this.networkProxies[proxyIndex];
const proxyPort = networkProxy.getListeningPort();
const proxyHost = 'localhost'; // Assuming NetworkProxy runs locally
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Forwarding TLS connection to NetworkProxy[${proxyIndex}] at ${proxyHost}:${proxyPort}`
);
}
// Create a connection to the NetworkProxy
const proxySocket = plugins.net.connect({
host: proxyHost,
port: proxyPort,
port: proxyPort
});
// Store the outgoing socket in the record
record.outgoing = proxySocket;
record.outgoingStartTime = Date.now();
record.usingNetworkProxy = true;
record.networkProxyIndex = proxyIndex;
// Set up error handlers
proxySocket.on('error', (err) => {
console.log(`[${connectionId}] Error connecting to NetworkProxy: ${err.message}`);
this.cleanupConnection(record, 'network_proxy_connect_error');
});
// Handle connection to NetworkProxy
proxySocket.on('connect', () => {
if (this.settings.enableDetailedLogging) {
console.log(`[${connectionId}] Connected to NetworkProxy at ${proxyHost}:${proxyPort}`);
}
// First send the initial data that contains the TLS ClientHello
proxySocket.write(initialData);
// Now set up bidirectional piping between client and NetworkProxy
socket.pipe(proxySocket);
proxySocket.pipe(socket);
// Setup cleanup handlers
proxySocket.on('close', () => {
if (this.settings.enableDetailedLogging) {
@ -492,39 +472,18 @@ export class PortProxy {
}
this.cleanupConnection(record, 'network_proxy_closed');
});
socket.on('close', () => {
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Client connection closed after forwarding to NetworkProxy`
);
console.log(`[${connectionId}] Client connection closed after forwarding to NetworkProxy`);
}
this.cleanupConnection(record, 'client_closed');
});
// Update activity on data transfer
socket.on('data', (chunk: Buffer) => {
this.updateActivity(record);
// Check for potential TLS renegotiation or reconnection packets
if (chunk.length > 0 && chunk[0] === 22) {
// ContentType.handshake
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Detected potential TLS handshake data while connected to NetworkProxy`
);
}
// NOTE: We don't need to explicitly forward the renegotiation packets
// because socket.pipe(proxySocket) is already handling that.
// The pipe ensures all data (including renegotiation) flows through properly.
// Just update the activity timestamp to prevent timeouts
record.lastActivity = Date.now();
}
});
socket.on('data', () => this.updateActivity(record));
proxySocket.on('data', () => this.updateActivity(record));
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] TLS connection successfully forwarded to NetworkProxy[${proxyIndex}]`
@ -532,7 +491,7 @@ export class PortProxy {
}
});
}
/**
* Sets up a direct connection to the target (original behavior)
* This is used when NetworkProxy isn't configured or as a fallback
@ -609,11 +568,11 @@ export class PortProxy {
// Apply socket optimizations
targetSocket.setNoDelay(this.settings.noDelay);
// Apply keep-alive settings to the outgoing connection as well
if (this.settings.keepAlive) {
targetSocket.setKeepAlive(true, this.settings.keepAliveInitialDelay);
// Apply enhanced TCP keep-alive options if enabled
if (this.settings.enableKeepAliveProbes) {
try {
@ -626,9 +585,7 @@ export class PortProxy {
} catch (err) {
// Ignore errors - these are optional enhancements
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Enhanced TCP keep-alive not supported for outgoing socket: ${err}`
);
console.log(`[${connectionId}] Enhanced TCP keep-alive not supported for outgoing socket: ${err}`);
}
}
}
@ -685,21 +642,19 @@ export class PortProxy {
// For keep-alive connections, just log a warning instead of closing
if (record.hasKeepAlive) {
console.log(
`[${connectionId}] Timeout event on incoming keep-alive connection from ${
record.remoteIP
} after ${plugins.prettyMs(
`[${connectionId}] Timeout event on incoming keep-alive connection from ${record.remoteIP} after ${plugins.prettyMs(
this.settings.socketTimeout || 3600000
)}. Connection preserved.`
);
// Don't close the connection - just log
return;
}
// For non-keep-alive connections, proceed with normal cleanup
console.log(
`[${connectionId}] Timeout on incoming side from ${
record.remoteIP
} after ${plugins.prettyMs(this.settings.socketTimeout || 3600000)}`
`[${connectionId}] Timeout on incoming side from ${record.remoteIP} after ${plugins.prettyMs(
this.settings.socketTimeout || 3600000
)}`
);
if (record.incomingTerminationReason === null) {
record.incomingTerminationReason = 'timeout';
@ -712,21 +667,19 @@ export class PortProxy {
// For keep-alive connections, just log a warning instead of closing
if (record.hasKeepAlive) {
console.log(
`[${connectionId}] Timeout event on outgoing keep-alive connection from ${
record.remoteIP
} after ${plugins.prettyMs(
`[${connectionId}] Timeout event on outgoing keep-alive connection from ${record.remoteIP} after ${plugins.prettyMs(
this.settings.socketTimeout || 3600000
)}. Connection preserved.`
);
// Don't close the connection - just log
return;
}
// For non-keep-alive connections, proceed with normal cleanup
console.log(
`[${connectionId}] Timeout on outgoing side from ${
record.remoteIP
} after ${plugins.prettyMs(this.settings.socketTimeout || 3600000)}`
`[${connectionId}] Timeout on outgoing side from ${record.remoteIP} after ${plugins.prettyMs(
this.settings.socketTimeout || 3600000
)}`
);
if (record.outgoingTerminationReason === null) {
record.outgoingTerminationReason = 'timeout';
@ -740,11 +693,9 @@ export class PortProxy {
// Disable timeouts completely for immortal connections
socket.setTimeout(0);
targetSocket.setTimeout(0);
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Disabled socket timeouts for immortal keep-alive connection`
);
console.log(`[${connectionId}] Disabled socket timeouts for immortal keep-alive connection`);
}
} else {
// Set normal timeouts for other connections
@ -774,7 +725,9 @@ export class PortProxy {
const combinedData = Buffer.concat(record.pendingData);
targetSocket.write(combinedData, (err) => {
if (err) {
console.log(`[${connectionId}] Error writing pending data to target: ${err.message}`);
console.log(
`[${connectionId}] Error writing pending data to target: ${err.message}`
);
return this.initiateCleanupOnce(record, 'write_error');
}
@ -793,9 +746,7 @@ export class PortProxy {
? ` (Port-based for domain: ${domainConfig.domains.join(', ')})`
: ''
}` +
` TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${
record.hasKeepAlive ? 'Yes' : 'No'
}`
` TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${record.hasKeepAlive ? 'Yes' : 'No'}`
);
} else {
console.log(
@ -826,9 +777,7 @@ export class PortProxy {
? ` (Port-based for domain: ${domainConfig.domains.join(', ')})`
: ''
}` +
` TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${
record.hasKeepAlive ? 'Yes' : 'No'
}`
` TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${record.hasKeepAlive ? 'Yes' : 'No'}`
);
} else {
console.log(
@ -850,28 +799,11 @@ export class PortProxy {
// Add the renegotiation listener for SNI validation
if (serverName) {
// This listener will check for TLS renegotiation attempts
// Note: We don't need to explicitly forward the renegotiation packets
// since socket.pipe(targetSocket) is already set up earlier and handles that
socket.on('data', (renegChunk: Buffer) => {
if (renegChunk.length > 0 && renegChunk.readUInt8(0) === 22) {
try {
// Try to extract SNI from potential renegotiation
const newSNI = extractSNI(renegChunk, this.settings.enableTlsDebugLogging);
// IMPORTANT: If we can't extract an SNI from renegotiation, we MUST allow it through
// Otherwise valid renegotiations that don't explicitly repeat the SNI will break
if (newSNI === undefined) {
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Rehandshake detected without SNI, allowing it through.`
);
}
// Let it pass through - this is critical for Chrome's TLS handling
return;
}
// Only block if we positively identify a different SNI
if (newSNI && newSNI !== record.lockedDomain) {
console.log(
`[${connectionId}] Rehandshake detected with different SNI: ${newSNI} vs locked ${record.lockedDomain}. Terminating connection.`
@ -883,8 +815,6 @@ export class PortProxy {
);
}
} catch (err) {
// Always allow the renegotiation to continue if we encounter an error
// This ensures Chrome can complete its TLS renegotiation
console.log(
`[${connectionId}] Error processing potential renegotiation: ${err}. Allowing connection to continue.`
);
@ -897,91 +827,52 @@ export class PortProxy {
if (record.cleanupTimer) {
clearTimeout(record.cleanupTimer);
}
// For immortal keep-alive connections, skip setting a timeout completely
if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') {
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Keep-alive connection with immortal treatment - no max lifetime`
);
console.log(`[${connectionId}] Keep-alive connection with immortal treatment - no max lifetime`);
}
// No cleanup timer for immortal connections
}
// For TLS keep-alive connections, use a more generous timeout now that
// we've fixed the renegotiation handling issue that was causing certificate problems
else if (record.hasKeepAlive && record.isTLS) {
// Use a longer timeout for TLS connections now that renegotiation handling is fixed
// This reduces unnecessary reconnections while still ensuring certificate freshness
const tlsKeepAliveTimeout = 4 * 60 * 60 * 1000; // 4 hours for TLS keep-alive - increased from 30 minutes
const safeTimeout = ensureSafeTimeout(tlsKeepAliveTimeout);
record.cleanupTimer = setTimeout(() => {
console.log(
`[${connectionId}] TLS keep-alive connection from ${
record.remoteIP
} exceeded max lifetime (${plugins.prettyMs(
tlsKeepAliveTimeout
)}), forcing cleanup to refresh certificate context.`
);
this.initiateCleanupOnce(record, 'tls_certificate_refresh');
}, safeTimeout);
// Make sure timeout doesn't keep the process alive
if (record.cleanupTimer.unref) {
record.cleanupTimer.unref();
}
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] TLS keep-alive connection with aggressive certificate refresh protection, lifetime: ${plugins.prettyMs(
tlsKeepAliveTimeout
)}`
);
}
}
}
// For extended keep-alive connections, use extended timeout
else if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'extended') {
const extendedTimeout = this.settings.extendedKeepAliveLifetime || 7 * 24 * 60 * 60 * 1000; // 7 days
const safeTimeout = ensureSafeTimeout(extendedTimeout);
record.cleanupTimer = setTimeout(() => {
console.log(
`[${connectionId}] Keep-alive connection from ${
record.remoteIP
} exceeded extended lifetime (${plugins.prettyMs(extendedTimeout)}), forcing cleanup.`
`[${connectionId}] Keep-alive connection from ${record.remoteIP} exceeded extended lifetime (${plugins.prettyMs(
extendedTimeout
)}), forcing cleanup.`
);
this.initiateCleanupOnce(record, 'extended_lifetime');
}, safeTimeout);
// Make sure timeout doesn't keep the process alive
if (record.cleanupTimer.unref) {
record.cleanupTimer.unref();
}
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Keep-alive connection with extended lifetime of ${plugins.prettyMs(
extendedTimeout
)}`
);
console.log(`[${connectionId}] Keep-alive connection with extended lifetime of ${plugins.prettyMs(extendedTimeout)}`);
}
}
// For standard connections, use normal timeout
else {
// Use domain-specific timeout if available, otherwise use default
const connectionTimeout =
record.domainConfig?.connectionTimeout || this.settings.maxConnectionLifetime!;
const connectionTimeout = record.domainConfig?.connectionTimeout || this.settings.maxConnectionLifetime!;
const safeTimeout = ensureSafeTimeout(connectionTimeout);
record.cleanupTimer = setTimeout(() => {
console.log(
`[${connectionId}] Connection from ${
record.remoteIP
} exceeded max lifetime (${plugins.prettyMs(connectionTimeout)}), forcing cleanup.`
`[${connectionId}] Connection from ${record.remoteIP} exceeded max lifetime (${plugins.prettyMs(
connectionTimeout
)}), forcing cleanup.`
);
this.initiateCleanupOnce(record, 'connection_timeout');
}, safeTimeout);
// Make sure timeout doesn't keep the process alive
if (record.cleanupTimer.unref) {
record.cleanupTimer.unref();
@ -1059,126 +950,6 @@ export class PortProxy {
this.terminationStats[side][reason] = (this.terminationStats[side][reason] || 0) + 1;
}
/**
* Update connection activity timestamp with sleep detection
*/
private updateActivity(record: IConnectionRecord): void {
// Get the current time
const now = Date.now();
// Check if there was a large time gap that suggests system sleep
if (record.lastActivity > 0) {
const timeDiff = now - record.lastActivity;
// If time difference is very large (> 30 minutes) and this is a keep-alive connection,
// this might indicate system sleep rather than just inactivity
if (timeDiff > 30 * 60 * 1000 && record.hasKeepAlive) {
if (this.settings.enableDetailedLogging) {
console.log(
`[${record.id}] Detected possible system sleep for ${plugins.prettyMs(timeDiff)}. ` +
`Handling keep-alive connection after long inactivity.`
);
}
// For TLS keep-alive connections after sleep/long inactivity, force close
// to make browser establish a new connection with fresh certificate context
if (record.isTLS && record.tlsHandshakeComplete) {
// More generous timeout now that we've fixed the renegotiation handling
if (timeDiff > 2 * 60 * 60 * 1000) {
// If inactive for more than 2 hours (increased from 20 minutes)
console.log(
`[${record.id}] TLS connection inactive for ${plugins.prettyMs(timeDiff)}. ` +
`Closing to force new connection with fresh certificate.`
);
return this.initiateCleanupOnce(record, 'certificate_refresh_needed');
} else if (timeDiff > 30 * 60 * 1000) {
// For shorter but still significant inactivity (30+ minutes), refresh TLS state
console.log(
`[${record.id}] TLS connection inactive for ${plugins.prettyMs(timeDiff)}. ` +
`Refreshing TLS state.`
);
this.refreshTlsStateAfterSleep(record);
// Add an additional check in 15 minutes if no activity
const refreshCheckId = record.id;
const refreshCheck = setTimeout(() => {
const currentRecord = this.connectionRecords.get(refreshCheckId);
if (currentRecord && Date.now() - currentRecord.lastActivity > 15 * 60 * 1000) {
console.log(
`[${refreshCheckId}] No activity detected after TLS refresh. ` +
`Closing connection to ensure certificate freshness.`
);
this.initiateCleanupOnce(currentRecord, 'tls_refresh_verification_failed');
}
}, 15 * 60 * 1000);
// Make sure timeout doesn't keep the process alive
if (refreshCheck.unref) {
refreshCheck.unref();
}
} else {
// For shorter inactivity periods, try to refresh the TLS state normally
this.refreshTlsStateAfterSleep(record);
}
}
// Mark that we detected sleep
record.possibleSystemSleep = true;
record.lastSleepDetection = now;
}
}
// Update the activity timestamp
record.lastActivity = now;
// Clear any inactivity warning
if (record.inactivityWarningIssued) {
record.inactivityWarningIssued = false;
}
}
/**
* Refresh TLS state after sleep detection
*/
private refreshTlsStateAfterSleep(record: IConnectionRecord): void {
// Skip if we're using a NetworkProxy as it handles its own TLS state
if (record.usingNetworkProxy) {
return;
}
try {
// For outgoing connections that might need to be refreshed
if (record.outgoing && !record.outgoing.destroyed) {
// Check how long this connection has been established
const connectionAge = Date.now() - record.incomingStartTime;
const hourInMs = 60 * 60 * 1000;
// For TLS browser connections, use a more generous timeout now that
// we've fixed the renegotiation handling issues
if (record.isTLS && record.hasKeepAlive && connectionAge > 8 * hourInMs) { // 8 hours instead of 45 minutes
console.log(
`[${record.id}] Long-lived TLS connection (${plugins.prettyMs(connectionAge)}). ` +
`Closing to ensure proper certificate handling on browser reconnect in proxy chain.`
);
return this.initiateCleanupOnce(record, 'certificate_context_refresh');
}
// For newer connections, try to send a refresh packet
record.outgoing.write(Buffer.alloc(0));
if (this.settings.enableDetailedLogging) {
console.log(`[${record.id}] Sent refresh packet after sleep detection`);
}
}
} catch (err) {
console.log(`[${record.id}] Error refreshing TLS state: ${err}`);
// If we hit an error, it's likely the connection is already broken
// Force cleanup to ensure browser reconnects cleanly
return this.initiateCleanupOnce(record, 'tls_refresh_error');
}
}
/**
* Cleans up a connection record.
* Destroys both incoming and outgoing sockets, clears timers, and removes the record.
@ -1276,9 +1047,7 @@ export class PortProxy {
` Duration: ${plugins.prettyMs(
duration
)}, Bytes IN: ${bytesReceived}, OUT: ${bytesSent}, ` +
`TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${
record.hasKeepAlive ? 'Yes' : 'No'
}` +
`TLS: ${record.isTLS ? 'Yes' : 'No'}, Keep-Alive: ${record.hasKeepAlive ? 'Yes' : 'No'}` +
`${record.usingNetworkProxy ? `, NetworkProxy: ${record.networkProxyIndex}` : ''}`
);
} else {
@ -1289,6 +1058,18 @@ export class PortProxy {
}
}
/**
* Update connection activity timestamp
*/
private updateActivity(record: IConnectionRecord): void {
record.lastActivity = Date.now();
// Clear any inactivity warning
if (record.inactivityWarningIssued) {
record.inactivityWarningIssued = false;
}
}
/**
* Get target IP with round-robin support
*/
@ -1301,7 +1082,7 @@ export class PortProxy {
}
return this.settings.targetIP!;
}
/**
* Initiates cleanup once for a connection
*/
@ -1309,15 +1090,12 @@ export class PortProxy {
if (this.settings.enableDetailedLogging) {
console.log(`[${record.id}] Connection cleanup initiated for ${record.remoteIP} (${reason})`);
}
if (
record.incomingTerminationReason === null ||
record.incomingTerminationReason === undefined
) {
if (record.incomingTerminationReason === null || record.incomingTerminationReason === undefined) {
record.incomingTerminationReason = reason;
this.incrementTerminationStat('incoming', reason);
}
this.cleanupConnection(record, reason);
}
@ -1441,7 +1219,7 @@ export class PortProxy {
// Apply socket optimizations
socket.setNoDelay(this.settings.noDelay);
// Create a unique connection ID and record
const connectionId = generateConnectionId();
const connectionRecord: IConnectionRecord = {
@ -1465,19 +1243,16 @@ export class PortProxy {
hasKeepAlive: false, // Will set to true if keep-alive is applied
incomingTerminationReason: null,
outgoingTerminationReason: null,
// Initialize NetworkProxy tracking fields
usingNetworkProxy: false,
// Initialize sleep detection fields
possibleSystemSleep: false,
usingNetworkProxy: false
};
// Apply keep-alive settings if enabled
if (this.settings.keepAlive) {
socket.setKeepAlive(true, this.settings.keepAliveInitialDelay);
connectionRecord.hasKeepAlive = true; // Mark connection as having keep-alive
// Apply enhanced TCP keep-alive options if enabled
if (this.settings.enableKeepAliveProbes) {
try {
@ -1491,9 +1266,7 @@ export class PortProxy {
} catch (err) {
// Ignore errors - these are optional enhancements
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Enhanced TCP keep-alive settings not supported: ${err}`
);
console.log(`[${connectionId}] Enhanced TCP keep-alive settings not supported: ${err}`);
}
}
}
@ -1506,8 +1279,8 @@ export class PortProxy {
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] New connection from ${remoteIP} on port ${localPort}. ` +
`Keep-Alive: ${connectionRecord.hasKeepAlive ? 'Enabled' : 'Disabled'}. ` +
`Active connections: ${this.connectionRecords.size}`
`Keep-Alive: ${connectionRecord.hasKeepAlive ? 'Enabled' : 'Disabled'}. ` +
`Active connections: ${this.connectionRecords.size}`
);
} else {
console.log(
@ -1645,12 +1418,12 @@ export class PortProxy {
)}`
);
}
// Check if we should forward this to a NetworkProxy
if (
isTlsHandshakeDetected &&
domainConfig.useNetworkProxy === true &&
initialChunk &&
isTlsHandshakeDetected &&
domainConfig.useNetworkProxy === true &&
initialChunk &&
this.networkProxies.length > 0
) {
return this.forwardToNetworkProxy(
@ -1888,11 +1661,11 @@ export class PortProxy {
} else {
nonTlsConnections++;
}
if (record.hasKeepAlive) {
keepAliveConnections++;
}
if (record.usingNetworkProxy) {
networkProxyConnections++;
}
@ -1933,80 +1706,35 @@ export class PortProxy {
}
// Skip inactivity check if disabled or for immortal keep-alive connections
if (
!this.settings.disableInactivityCheck &&
!(record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal')
) {
if (!this.settings.disableInactivityCheck &&
!(record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal')) {
const inactivityTime = now - record.lastActivity;
// Special handling for TLS keep-alive connections
if (
record.hasKeepAlive &&
record.isTLS &&
inactivityTime > this.settings.inactivityTimeout! / 2
) {
// For TLS keep-alive connections that are getting stale, try to refresh before closing
if (!record.inactivityWarningIssued) {
console.log(
`[${id}] TLS keep-alive connection from ${
record.remoteIP
} inactive for ${plugins.prettyMs(inactivityTime)}. ` +
`Attempting to preserve connection.`
);
// Set warning flag but give a much longer grace period for TLS connections
record.inactivityWarningIssued = true;
// For TLS connections, extend the last activity time considerably
// This gives browsers more time to re-establish the connection properly
record.lastActivity = now - this.settings.inactivityTimeout! / 3;
// Try to stimulate the connection with a probe packet
if (record.outgoing && !record.outgoing.destroyed) {
try {
// For TLS connections, send a proper TLS heartbeat-like packet
// This is just a small empty buffer that won't affect the TLS session
record.outgoing.write(Buffer.alloc(0));
if (this.settings.enableDetailedLogging) {
console.log(`[${id}] Sent TLS keep-alive probe packet`);
}
} catch (err) {
console.log(`[${id}] Error sending TLS probe packet: ${err}`);
}
}
// Don't proceed to the normal inactivity check logic
continue;
}
}
// Use extended timeout for extended-treatment keep-alive connections
let effectiveTimeout = this.settings.inactivityTimeout!;
if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'extended') {
const multiplier = this.settings.keepAliveInactivityMultiplier || 6;
effectiveTimeout = effectiveTimeout * multiplier;
}
if (inactivityTime > effectiveTimeout && !record.connectionClosed) {
// For keep-alive connections, issue a warning first
if (record.hasKeepAlive && !record.inactivityWarningIssued) {
console.log(
`[${id}] Warning: Keep-alive connection from ${
record.remoteIP
} inactive for ${plugins.prettyMs(inactivityTime)}. ` +
`Will close in 10 minutes if no activity.`
`[${id}] Warning: Keep-alive connection from ${record.remoteIP} inactive for ${plugins.prettyMs(inactivityTime)}. ` +
`Will close in 10 minutes if no activity.`
);
// Set warning flag and add grace period
record.inactivityWarningIssued = true;
record.lastActivity = now - (effectiveTimeout - 600000);
// Try to stimulate activity with a probe packet
if (record.outgoing && !record.outgoing.destroyed) {
try {
record.outgoing.write(Buffer.alloc(0));
if (this.settings.enableDetailedLogging) {
console.log(`[${id}] Sent probe packet to test keep-alive connection`);
}
@ -2015,48 +1743,18 @@ export class PortProxy {
}
}
} else {
// MODIFIED: For TLS connections, be more lenient before closing
// For TLS browser connections, we need to handle certificate context properly
if (record.isTLS && record.hasKeepAlive) {
// For very long inactivity, it's better to close the connection
// so the browser establishes a new one with a fresh certificate context
if (inactivityTime > 6 * 60 * 60 * 1000) {
// 6 hours
console.log(
`[${id}] TLS keep-alive connection from ${
record.remoteIP
} inactive for ${plugins.prettyMs(inactivityTime)}. ` +
`Closing to ensure proper certificate handling on browser reconnect.`
);
this.cleanupConnection(record, 'tls_certificate_refresh');
} else {
// For shorter inactivity periods, add grace period
console.log(
`[${id}] TLS keep-alive connection from ${
record.remoteIP
} inactive for ${plugins.prettyMs(inactivityTime)}. ` +
`Adding extra grace period.`
);
// Give additional time for browsers to reconnect properly
record.lastActivity = now - effectiveTimeout / 2;
}
} else {
// For non-keep-alive or after warning, close the connection
console.log(
`[${id}] Inactivity check: No activity on connection from ${record.remoteIP} ` +
`for ${plugins.prettyMs(inactivityTime)}.` +
(record.hasKeepAlive ? ' Despite keep-alive being enabled.' : '')
);
this.cleanupConnection(record, 'inactivity');
}
// For non-keep-alive or after warning, close the connection
console.log(
`[${id}] Inactivity check: No activity on connection from ${record.remoteIP} ` +
`for ${plugins.prettyMs(inactivityTime)}.` +
(record.hasKeepAlive ? ' Despite keep-alive being enabled.' : '')
);
this.cleanupConnection(record, 'inactivity');
}
} else if (inactivityTime <= effectiveTimeout && record.inactivityWarningIssued) {
// If activity detected after warning, clear the warning
if (this.settings.enableDetailedLogging) {
console.log(
`[${id}] Connection activity detected after inactivity warning, resetting warning`
);
console.log(`[${id}] Connection activity detected after inactivity warning, resetting warning`);
}
record.inactivityWarningIssued = false;
}
@ -2205,4 +1903,4 @@ export class PortProxy {
console.log('PortProxy shutdown complete.');
}
}
}