UNPKG

netkitty

Version:
150 lines (149 loc) 6.06 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PcapParser = void 0; const events_1 = __importDefault(require("events")); const node_fs_1 = require("node:fs"); const node_util_1 = require("node:util"); const GLOBAL_HEADER_LENGTH = 24; //bytes const PACKET_HEADER_LENGTH = 16; //bytes class PcapParser extends events_1.default { static parse(input) { return new PcapParser(input); } constructor(input) { super(); this.errored = false; this.index = 0; this.offset = 0; this.stream = (typeof input === 'string') ? (0, node_fs_1.createReadStream)(input) : input; this.stream.pause(); this.stream.on('data', (data) => this.onData(data)); this.stream.on('error', (err) => this.onError(err)); this.stream.on('end', () => this.onEnd()); this.buffer = null; this.state = () => this.parseGlobalHeader(); this.endianness = null; process.nextTick(this.stream.resume.bind(this.stream)); } updateBuffer(data) { if (data === null || data === undefined) return; if (this.buffer === null) { this.buffer = data; } else { let extendedBuffer = Buffer.alloc(this.buffer.length + data.length); this.buffer.copy(extendedBuffer); data.copy(extendedBuffer, this.buffer.length); this.buffer = extendedBuffer; } } parseGlobalHeader() { const buffer = this.buffer; if (buffer.length >= GLOBAL_HEADER_LENGTH) { let msg; const magicNumber = buffer.toString('hex', 0, 4); // determine pcap endianness if (magicNumber == 'a1b2c3d4') { this.endianness = 'BE'; } else if (magicNumber == 'd4c3b2a1' || magicNumber == '4d3cb2a1') { this.endianness = 'LE'; } else { this.errored = true; this.stream.pause(); msg = (0, node_util_1.format)('unknown magic number: %s', magicNumber); this.emit('error', new Error(msg)); this.onEnd(); return false; } const header = { magicNumber: buffer['readUInt32' + this.endianness](0, true), majorVersion: buffer['readUInt16' + this.endianness](4, true), minorVersion: buffer['readUInt16' + this.endianness](6, true), gmtOffset: buffer['readInt32' + this.endianness](8, true), timestampAccuracy: buffer['readUInt32' + this.endianness](12, true), snapshotLength: buffer['readUInt32' + this.endianness](16, true), linkLayerType: buffer['readUInt32' + this.endianness](20, true) }; if (header.majorVersion != 2 && header.minorVersion != 4) { this.errored = true; this.stream.pause(); msg = (0, node_util_1.format)('unsupported version %d.%d. pcap-parser only parses libpcap file format 2.4', header.majorVersion, header.minorVersion); this.emit('error', new Error(msg)); this.onEnd(); } else { this.emit('globalHeader', header); this.buffer = buffer.subarray(GLOBAL_HEADER_LENGTH); this.state = () => this.parsePacketHeader(); this.offset = GLOBAL_HEADER_LENGTH; return true; } } return false; } parsePacketHeader() { const buffer = this.buffer; if (buffer.length >= PACKET_HEADER_LENGTH) { const header = { timestampSeconds: buffer['readUInt32' + this.endianness](0, true), timestampMicroseconds: buffer['readUInt32' + this.endianness](4, true), capturedLength: buffer['readUInt32' + this.endianness](8, true), originalLength: buffer['readUInt32' + this.endianness](12, true) }; this.currentPacketHeader = header; this.emit('packetHeader', header); this.buffer = buffer.subarray(PACKET_HEADER_LENGTH); this.state = () => this.parsePacketBody(); this.index += 1; return true; } return false; } parsePacketBody() { const buffer = this.buffer; if (buffer.length >= this.currentPacketHeader.capturedLength) { const data = buffer.subarray(0, this.currentPacketHeader.capturedLength); const packetLength = data.length; const recordLength = PACKET_HEADER_LENGTH + packetLength; const pcapPacketInfo = { index: this.index, offset: this.offset, length: recordLength, recordHeaderOffset: this.offset, recordHeaderLength: PACKET_HEADER_LENGTH, packetOffset: this.offset + PACKET_HEADER_LENGTH, packetLength: data.length, seconds: this.currentPacketHeader.timestampSeconds, microseconds: this.currentPacketHeader.timestampMicroseconds, packet: data.toString('base64') }; this.emit('packetData', data); this.emit('packet', pcapPacketInfo); this.buffer = buffer.subarray(this.currentPacketHeader.capturedLength); this.state = () => this.parsePacketHeader(); this.offset += recordLength; return true; } return false; } onData(data) { if (this.errored) return; this.updateBuffer(data); while (this.state()) { } } onError(err) { this.emit('error', err); } onEnd() { this.emit('end'); } } exports.PcapParser = PcapParser;