This commit is contained in:
2025-05-22 09:22:55 +00:00
parent a4353b10bb
commit d584f3584c
7 changed files with 727 additions and 44 deletions

View File

@ -6,8 +6,9 @@
import * as plugins from '../../../plugins.js';
import type { IConnectionManager } from './interfaces.js';
import type { ISessionManager } from './interfaces.js';
import { SmtpResponseCode, SMTP_DEFAULTS } from './constants.js';
import { SmtpResponseCode, SMTP_DEFAULTS, SmtpState } from './constants.js';
import { SmtpLogger } from './utils/logging.js';
import { adaptiveLogger } from './utils/adaptive-logging.js';
import { getSocketDetails, formatMultilineResponse } from './utils/helpers.js';
/**
@ -95,9 +96,9 @@ export class ConnectionManager implements IConnectionManager {
this.sessionManager = sessionManager;
this.commandHandler = commandHandler;
// Default values for resource management - adjusted for testing
const DEFAULT_MAX_CONNECTIONS_PER_IP = 20; // Increased to allow tests with multiple connections
const DEFAULT_CONNECTION_RATE_LIMIT = 100; // Increased for test environments
// Default values for resource management - adjusted for production scalability
const DEFAULT_MAX_CONNECTIONS_PER_IP = 50; // Increased to support high-concurrency scenarios
const DEFAULT_CONNECTION_RATE_LIMIT = 200; // Increased for production load handling
const DEFAULT_CONNECTION_RATE_WINDOW = 60 * 1000; // 60 seconds window
const DEFAULT_BUFFER_SIZE_LIMIT = 10 * 1024 * 1024; // 10 MB
const DEFAULT_RESOURCE_CHECK_INTERVAL = 30 * 1000; // 30 seconds
@ -362,9 +363,12 @@ export class ConnectionManager implements IConnectionManager {
// Create a session for this connection
this.sessionManager.createSession(socket, false);
// Log the new connection
// Log the new connection using adaptive logger
const socketDetails = getSocketDetails(socket);
SmtpLogger.logConnection(socket, 'connect');
adaptiveLogger.logConnection(socket, 'connect');
// Update adaptive logger with current connection count
adaptiveLogger.updateConnectionCount(this.connectionStats.activeConnections);
// Send greeting
this.sendGreeting(socket);
@ -515,8 +519,11 @@ export class ConnectionManager implements IConnectionManager {
// Create a session for this connection
this.sessionManager.createSession(socket, true);
// Log the new secure connection
SmtpLogger.logConnection(socket, 'connect');
// Log the new secure connection using adaptive logger
adaptiveLogger.logConnection(socket, 'connect');
// Update adaptive logger with current connection count
adaptiveLogger.updateConnectionCount(this.connectionStats.activeConnections);
// Send greeting
this.sendGreeting(socket);
@ -551,6 +558,23 @@ export class ConnectionManager implements IConnectionManager {
this.sessionManager.updateSessionActivity(session);
}
// Check if we're in DATA receiving mode - handle differently
if (session && session.state === SmtpState.DATA_RECEIVING) {
// In DATA mode, pass raw chunks directly to command handler with special marker
// Don't line-buffer large email content
try {
const dataString = data.toString('utf8');
// Use a special prefix to indicate this is raw data, not a command line
this.commandHandler(socket, `__RAW_DATA__${dataString}`);
return;
} catch (dataError) {
SmtpLogger.error(`Data handler error during DATA mode: ${dataError instanceof Error ? dataError.message : String(dataError)}`);
socket.destroy();
return;
}
}
// For command mode, continue with line-buffered processing
// Check buffer size limits to prevent memory attacks
totalBytesReceived += data.length;
@ -689,6 +713,12 @@ export class ConnectionManager implements IConnectionManager {
// Clear active connections
this.activeConnections.clear();
// Stop resource monitoring to prevent hanging timers
if (this.resourceCheckInterval) {
clearInterval(this.resourceCheckInterval);
this.resourceCheckInterval = null;
}
}
/**
@ -728,7 +758,10 @@ export class ConnectionManager implements IConnectionManager {
}
// Log connection close with session details if available
SmtpLogger.logConnection(socket, 'close', session);
adaptiveLogger.logConnection(socket, 'close', session);
// Update adaptive logger with new connection count
adaptiveLogger.updateConnectionCount(this.connectionStats.activeConnections);
} catch (error) {
// Handle any unexpected errors during cleanup
SmtpLogger.error(`Error in handleSocketClose: ${error instanceof Error ? error.message : String(error)}`);
@ -765,8 +798,8 @@ export class ConnectionManager implements IConnectionManager {
remotePort: socketDetails.remotePort
});
// Log the error for connection tracking
SmtpLogger.logConnection(socket, 'error', session, error);
// Log the error for connection tracking using adaptive logger
adaptiveLogger.logConnection(socket, 'error', session, error);
// Cancel any timeout ID stored in the session
if (session?.dataTimeoutId) {
@ -921,7 +954,7 @@ export class ConnectionManager implements IConnectionManager {
private sendResponse(socket: plugins.net.Socket | plugins.tls.TLSSocket, response: string): void {
try {
socket.write(`${response}${SMTP_DEFAULTS.CRLF}`);
SmtpLogger.logResponse(response, socket);
adaptiveLogger.logResponse(response, socket);
} catch (error) {
// Log error and destroy socket
SmtpLogger.error(`Error sending response: ${error instanceof Error ? error.message : String(error)}`, {