/** * SMB2 Echo Command Handler * Handles SMB2_ECHO requests and responses for connection keep-alive */ import type { SMB2Connection, SMB2Session, SMB2TreeConnect, SMB2CommandHandler, } from '../protocol/types.js'; import { SMB2_STATUS, SMB2_HEADER_SIZE, SMB2_COMMANDS, } from '../protocol/constants.js'; import { Logger } from '../utils/logger.js'; export class SMB2EchoHandler { private readonly logger: Logger; constructor() { this.logger = new Logger('SMB2EchoHandler'); } public async handle( requestData: Buffer, connection: SMB2Connection, session?: SMB2Session, _treeConnect?: SMB2TreeConnect, ): Promise { try { this.logger.debug(`Echo request from ${connection.clientAddress}`); // Validate request data this.validateEchoRequest(requestData); // Echo requests typically have minimal structure // The response should echo back the same data that was sent // For SMB2 Echo, the request structure is: // - StructureSize (2 bytes): Should be 4 // - Reserved (2 bytes): Should be 0 if (requestData.length < 4) { throw new Error('Echo request too short'); } const structureSize = requestData.readUInt16LE(0); const reserved = requestData.readUInt16LE(2); this.logger.debug(`Echo request - Structure size: ${structureSize}, Reserved: ${reserved}`); // Validate structure size if (structureSize !== 4) { throw new Error(`Invalid echo structure size: ${structureSize}`); } // Create echo response (same structure as request) const responseBuffer = Buffer.alloc(4); responseBuffer.writeUInt16LE(4, 0); // Structure size responseBuffer.writeUInt16LE(0, 2); // Reserved // Update connection last activity time (connection as any).lastActivityTime = new Date(); this.logger.debug(`Echo response sent to ${connection.clientAddress}`); return responseBuffer; } catch (error) { this.logger.error('Error handling echo request:', error); throw error; } } /** * Validate echo request parameters */ private validateEchoRequest(requestData: Buffer): void { if (requestData.length < 4) { throw new Error('Echo request data too short'); } if (requestData.length > 1024) { throw new Error('Echo request data too long'); } } /** * Get echo statistics for monitoring */ public getEchoStats(): { totalEchoes: number; lastEchoTime: Date | null; } { // This would be implemented to track echo statistics // For now, return default values return { totalEchoes: 0, lastEchoTime: null, }; } /** * Check connection health based on echo patterns */ public checkConnectionHealth(connection: SMB2Connection): { isHealthy: boolean; lastActivity: Date; timeSinceLastActivity: number; } { const now = new Date(); const lastActivity = connection.lastActivityTime; const timeSinceLastActivity = now.getTime() - lastActivity.getTime(); // Consider connection healthy if activity within last 5 minutes const isHealthy = timeSinceLastActivity < 300000; // 5 minutes return { isHealthy, lastActivity, timeSinceLastActivity, }; } /** * Handle echo timeout scenarios */ public handleEchoTimeout(connection: SMB2Connection): void { this.logger.warn(`Echo timeout for connection ${connection.connectionId}`); // In a full implementation, this might: // - Mark connection as potentially stale // - Trigger connection cleanup // - Update health metrics } }