This commit is contained in:
2025-05-21 14:28:33 +00:00
parent 38811dbf23
commit 10ab09894b
8 changed files with 652 additions and 162 deletions

View File

@ -195,51 +195,82 @@ export class SmtpServer implements ISmtpServer {
// Start secure server if configured
if (this.options.securePort && this.tlsHandler.isTlsEnabled()) {
this.secureServer = this.tlsHandler.createSecureServer();
if (this.secureServer) {
this.secureServer.on('secureConnection', (socket) => {
// Check IP reputation before handling connection
this.securityHandler.checkIpReputation(socket)
.then(allowed => {
if (allowed) {
this.connectionManager.handleNewSecureConnection(socket);
} else {
// Close connection if IP is not allowed
socket.destroy();
}
})
.catch(error => {
SmtpLogger.error(`IP reputation check error: ${error instanceof Error ? error.message : String(error)}`, {
remoteAddress: socket.remoteAddress,
error: error instanceof Error ? error : new Error(String(error))
});
// Allow connection on error (fail open)
this.connectionManager.handleNewSecureConnection(socket);
try {
this.secureServer = this.tlsHandler.createSecureServer();
if (this.secureServer) {
// Use explicit error handling for secure connections
this.secureServer.on('tlsClientError', (err, tlsSocket) => {
SmtpLogger.error(`TLS client error: ${err.message}`, {
error: err,
remoteAddress: tlsSocket.remoteAddress,
remotePort: tlsSocket.remotePort,
stack: err.stack
});
});
this.secureServer.on('error', (err) => {
SmtpLogger.error(`SMTP secure server error: ${err.message}`, { error: err });
});
// Start listening on secure port
await new Promise<void>((resolve, reject) => {
if (!this.secureServer) {
reject(new Error('Secure server not initialized'));
return;
}
this.secureServer.listen(this.options.securePort, this.options.host, () => {
SmtpLogger.info(`SMTP secure server listening on ${this.options.host || '0.0.0.0'}:${this.options.securePort}`);
resolve();
// No need to destroy, the error event will handle that
});
this.secureServer.on('error', reject);
// Register the secure connection handler
this.secureServer.on('secureConnection', (socket) => {
SmtpLogger.info(`New secure connection from ${socket.remoteAddress}:${socket.remotePort}`, {
protocol: socket.getProtocol(),
cipher: socket.getCipher()?.name
});
// Check IP reputation before handling connection
this.securityHandler.checkIpReputation(socket)
.then(allowed => {
if (allowed) {
// Pass the connection to the connection manager
this.connectionManager.handleNewSecureConnection(socket);
} else {
// Close connection if IP is not allowed
socket.destroy();
}
})
.catch(error => {
SmtpLogger.error(`IP reputation check error: ${error instanceof Error ? error.message : String(error)}`, {
remoteAddress: socket.remoteAddress,
error: error instanceof Error ? error : new Error(String(error)),
stack: error instanceof Error ? error.stack : 'No stack trace available'
});
// Allow connection on error (fail open)
this.connectionManager.handleNewSecureConnection(socket);
});
});
// Global error handler for the secure server
this.secureServer.on('error', (err) => {
SmtpLogger.error(`SMTP secure server error: ${err.message}`, {
error: err,
stack: err.stack
});
});
// Start listening on secure port
await new Promise<void>((resolve, reject) => {
if (!this.secureServer) {
reject(new Error('Secure server not initialized'));
return;
}
this.secureServer.listen(this.options.securePort, this.options.host, () => {
SmtpLogger.info(`SMTP secure server listening on ${this.options.host || '0.0.0.0'}:${this.options.securePort}`);
resolve();
});
// Only use error event for startup issues
this.secureServer.once('error', reject);
});
} else {
SmtpLogger.warn('Failed to create secure server, TLS may not be properly configured');
}
} catch (error) {
SmtpLogger.error(`Error setting up secure server: ${error instanceof Error ? error.message : String(error)}`, {
error: error instanceof Error ? error : new Error(String(error)),
stack: error instanceof Error ? error.stack : 'No stack trace available'
});
} else {
SmtpLogger.warn('Failed to create secure server, TLS may not be properly configured');
}
}