UNPKG

netkitty

Version:
264 lines (263 loc) 7.88 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PcapReader = void 0; const events_1 = __importDefault(require("events")); const promises_1 = require("node:fs/promises"); const duplexpair_1 = __importDefault(require("duplexpair")); const PcapParser_1 = require("./PcapParser"); class PcapReader extends events_1.default { get readStream() { return this.duplexPair.socket2; } get writeStream() { return this.duplexPair.socket1; } constructor(options) { super(); this.chunkSize = 1518 * 10; this.index = 0; this.offset = 0; this.readDone = false; this.readBufferFileHandle = null; this.paused = false; this.filename = options.filename; this.watch = !!options.watch; this.chunkSize = options.chunkSize ? options.chunkSize : this.chunkSize; if (options.onPacket) this.onPacket = options.onPacket; if (options.onStart) this.onStart = options.onStart; if (options.onStop) this.onStop = options.onStop; if (options.onDone) this.onDone = options.onDone; if (options.onError) this.onError = options.onError; } /** * Pause read * @protected */ pauseRead() { this.readStream.pause(); this.paused = true; } /** * Resume read * @protected */ resumeRead() { this.readStream.resume(); this.paused = false; } /** * Initialize reader * @protected */ initReader() { this.duplexPair = new duplexpair_1.default(); this.parser = PcapParser_1.PcapParser.parse(this.readStream); this.parser .on('packet', async (pcapPacketInfo) => { this.index = pcapPacketInfo.index; this.emit('packet', pcapPacketInfo); if (this.onPacket) { this.pauseRead(); await this.onPacket(pcapPacketInfo); this.resumeRead(); } }) .on('error', (err) => { this.emit('error', err); if (this.onError) this.onError(err); }); } /** * Reset reader * @protected */ async reset() { await this.stop(); this.parser?.removeAllListeners(); this.index = 0; this.offset = 0; this.paused = false; this.initReader(); } /** * Initialize read packet file handle * @protected */ async initReadPacketFileHandle() { return await (0, promises_1.open)(this.filename, 'r'); } /** * Initialize read buffer file handle * @protected */ async initReadBufferFileHandle() { if (!this.readBufferFileHandle) this.readBufferFileHandle = await (0, promises_1.open)(this.filename, 'r'); return this.readBufferFileHandle; } /** * Read file buffer * @protected */ async readBuffer() { const readBufferFileHandle = await this.initReadBufferFileHandle(); try { const result = await readBufferFileHandle.read({ buffer: Buffer.alloc(this.chunkSize), offset: 0, length: this.chunkSize, position: this.offset }); if (result.bytesRead <= 0) return true; const data = Buffer.alloc(result.bytesRead); result.buffer.copy(data, 0, 0, result.bytesRead); this.offset += result.bytesRead; this.writeStream.write(data); return false; } catch (e) { return true; } } /** * Read file continually * @protected */ continualRead() { process.nextTick(async () => { let read = true; this.once('stop', () => read = false); let isReachEnd = false; while (read || !isReachEnd) { if (this.paused) { await new Promise(resolve => setTimeout(resolve, 1)); continue; } isReachEnd = await this.readBuffer(); if (isReachEnd) { await new Promise(resolve => setTimeout(resolve, 1)); } } await this.readBufferFileHandle?.close(); this.readBufferFileHandle = null; this.readDone = true; this.emit('done'); if (this.onDone) await this.onDone(); }); } /** * Read the file straight * @protected */ straightRead() { process.nextTick(async () => { let isReachEnd = false; let stopped = false; this.once('stop', () => stopped = true); while (!isReachEnd && !stopped) { if (this.paused) { await new Promise(resolve => setTimeout(resolve, 1)); continue; } isReachEnd = await this.readBuffer(); } this.readDone = true; if (!stopped) await this.stop(); await this.readBufferFileHandle?.close(); this.readBufferFileHandle = null; this.emit('done'); if (this.onDone) await this.onDone(); }); } /** * Read packet data by record's offset and record's length * @param offset * @param length */ async readPacket(offset, length) { const fileHandle = await this.initReadPacketFileHandle(); const recordHeaderLength = 16; const packetLength = length - recordHeaderLength; const result = await fileHandle.read({ buffer: Buffer.alloc(packetLength), offset: 0, length: packetLength, position: offset + recordHeaderLength }); await fileHandle.close(); return result.buffer; } /** * Start reading pcap */ async start() { await this.reset(); this.emit('start'); if (this.onStart) await this.onStart(); if (this.watch) { this.continualRead(); } else { this.straightRead(); } } /** * Stop reading pcap */ async stop() { if (this.parser) { this.emit('stop'); if (!this.readDone) await new Promise(resolve => this.once('done', resolve)); if (this.onStop) await this.onStop(); } if (this.duplexPair) { await new Promise(resolve => { if (this.writeStream.closed) return resolve(); this.writeStream.once('close', () => resolve()); this.writeStream.once('error', err => !!err); this.writeStream.destroy(); }); await new Promise(resolve => { if (this.readStream.closed) return resolve(); this.readStream.once('close', () => resolve()); this.readStream.once('error', err => !!err); this.readStream.destroy(); }); } } /** * Close pcap reader */ async close() { await this.stop(); this.emit('close'); this.removeAllListeners(); } on(eventName, listener) { super.on(eventName, listener); return this; } once(eventName, listener) { super.once(eventName, listener); return this; } } exports.PcapReader = PcapReader;