UNPKG

netkitty

Version:
340 lines (339 loc) 16.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IPv4 = void 0; const BaseHeader_1 = require("../abstracts/BaseHeader"); const NumberToHex_1 = require("../../helper/NumberToHex"); const StringContentEncodingEnum_1 = require("../lib/StringContentEncodingEnum"); const BufferToNumber_1 = require("../../helper/BufferToNumber"); const NumberToBuffer_1 = require("../../helper/NumberToBuffer"); const BufferToHex_1 = require("../../helper/BufferToHex"); const IPToBuffer_1 = require("../../helper/IPToBuffer"); const BufferToIP_1 = require("../../helper/BufferToIP"); const HexToBuffer_1 = require("../../helper/HexToBuffer"); class IPv4 extends BaseHeader_1.BaseHeader { constructor() { super(...arguments); this.SCHEMA = { type: 'object', properties: { version: { type: 'integer', label: 'Version', minimum: 0, maximum: 15, decode: () => { this.instance.version.setValue(this.readBits(0, 1, 0, 4)); if (this.instance.version.getValue() !== 4) this.recordError(this.instance.version.getPath(), 'IPv4 version should be 4'); }, encode: () => { let version = this.instance.version.getValue(4); version = version > 15 ? 15 : version; version = version < 0 ? 0 : version; if (version !== 4) this.recordError(this.instance.version.getPath(), 'IPv4 version should be 4'); this.instance.version.setValue(version); this.writeBits(0, 1, 0, 4, version); } }, hdrLen: { type: 'integer', label: 'Header Length', minimum: 20, maximum: 60, decode: () => { this.instance.hdrLen.setValue(this.readBits(0, 1, 4, 4) * 4); }, encode: () => { let headerLength = this.instance.hdrLen.getValue(0); if (headerLength) headerLength = headerLength ? Math.floor(headerLength / 4) : 0; this.writeBits(0, 1, 4, 4, headerLength); if (!headerLength) this.addPostSelfEncodeHandler(() => { this.instance.hdrLen.setValue(this.length); this.writeBits(0, 1, 4, 4, Math.floor(this.length / 4)); }, 10); } }, dsfield: { type: 'object', label: 'Differentiated Services Field', properties: { dscp: { type: 'integer', minimum: 0, maximum: 63, label: 'Differentiated Services Codepoint', decode: () => { this.instance.dsfield.dscp.setValue(this.readBits(1, 1, 0, 6)); }, encode: () => { const dscp = this.instance.dsfield.dscp.getValue(0); this.instance.dsfield.dscp.setValue(dscp); this.writeBits(1, 1, 0, 6, dscp); } }, ecn: { type: 'integer', label: 'Explicit Congestion Notification', decode: () => { this.instance.dsfield.ecn.setValue(this.readBits(1, 1, 6, 2)); }, encode: () => { const ecn = this.instance.dsfield.ecn.getValue(0); this.instance.dsfield.ecn.setValue(ecn); this.writeBits(1, 1, 6, 2, ecn); } } } }, length: { type: 'integer', label: 'Total Length', minimum: 0, maximum: 65535, decode: () => { this.instance.length.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(2, 2))); }, encode: () => { //This field's real value needs down stream codec invoke recode to fill const length = this.instance.length.getValue(0); if (length) { this.writeBytes(2, (0, NumberToBuffer_1.UInt16ToBuffer)(length)); } else { this.writeBytes(2, (0, NumberToBuffer_1.UInt16ToBuffer)(length)); this.addPostPacketEncodeHandler(() => { let startCount = false; let totalLength = 0; this.codecModules.forEach((codecModule) => { if (codecModule === this) startCount = true; if (startCount) totalLength += codecModule.length; }); this.instance.length.setValue(totalLength); this.writeBytes(2, (0, NumberToBuffer_1.UInt16ToBuffer)(totalLength)); }, 1); } } }, id: { type: 'integer', label: 'Identification', minimum: 0, maximum: 65535, decode: () => { this.instance.id.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(4, 2))); }, encode: () => { const id = this.instance.id.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.id.setValue(id); this.writeBytes(4, (0, NumberToBuffer_1.UInt16ToBuffer)(id)); } }, flags: { type: 'object', label: 'Flags', properties: { rb: { type: 'integer', enum: [0, 1], label: 'Reserved bit', decode: () => { this.instance.flags.rb.setValue(this.readBits(6, 1, 0, 1)); }, encode: () => { const rb = this.instance.flags.rb.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.flags.rb.setValue(rb); this.writeBits(6, 1, 0, 1, rb); } }, df: { type: 'integer', enum: [0, 1], label: 'Don\'t fragment', decode: () => { this.instance.flags.df.setValue(this.readBits(6, 1, 1, 1)); }, encode: () => { const df = this.instance.flags.df.getValue(1, (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.flags.df.setValue(df); this.writeBits(6, 1, 1, 1, df); } }, mf: { type: 'integer', enum: [0, 1], label: 'More fragments', decode: () => { this.instance.flags.mf.setValue(this.readBits(6, 1, 2, 1)); }, encode: () => { const mf = this.instance.flags.mf.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.flags.mf.setValue(mf); this.writeBits(6, 1, 2, 1, mf); } } } }, fragOffset: { type: 'integer', minimum: 0, maximum: 8191, label: 'Fragment Offset', decode: () => { this.instance.fragOffset.setValue(this.readBits(6, 2, 3, 13)); }, encode: () => { const fragOffset = this.instance.fragOffset.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.fragOffset.setValue(fragOffset); this.writeBits(6, 2, 3, 13, fragOffset); } }, ttl: { type: 'integer', minimum: 0, maximum: 255, label: 'Time to Live', decode: () => { this.instance.ttl.setValue((0, BufferToNumber_1.BufferToUInt8)(this.readBytes(8, 1))); }, encode: () => { const ttl = this.instance.ttl.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.ttl.setValue(ttl); this.writeBytes(8, (0, NumberToBuffer_1.UInt8ToBuffer)(ttl)); } }, protocol: { type: 'integer', label: 'Protocol', minimum: 0, maximum: 255, decode: () => { this.instance.protocol.setValue((0, BufferToNumber_1.BufferToUInt8)(this.readBytes(9, 1))); }, encode: () => { const protocol = this.instance.protocol.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.protocol.setValue(protocol); this.writeBytes(9, (0, NumberToBuffer_1.UInt8ToBuffer)(protocol)); } }, checksum: { type: 'integer', label: 'Header Checksum', minimum: 0, maximum: 65535, decode: () => { this.instance.checksum.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(10, 2))); }, encode: () => { let checksum = this.instance.checksum.getValue(0); checksum = checksum > 65535 ? 65535 : checksum; checksum = checksum < 0 ? 0 : checksum; if (checksum) { this.instance.checksum.setValue(checksum); this.writeBytes(10, (0, NumberToBuffer_1.UInt16ToBuffer)(checksum)); } else { this.instance.checksum.setValue(checksum); this.writeBytes(10, (0, NumberToBuffer_1.UInt16ToBuffer)(checksum)); this.addPostPacketEncodeHandler(() => { const calcChecksum = this.calculateIPv4Checksum(this.packet.subarray(this.startPos, this.endPos)); this.instance.checksum.setValue(calcChecksum); this.writeBytes(10, (0, NumberToBuffer_1.UInt16ToBuffer)(calcChecksum)); }, 2); } } }, sip: { type: 'string', label: 'Source Address', minLength: 7, maxLength: 15, contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.IPv4, decode: () => { const sipBuffer = this.readBytes(12, 4); this.instance.sip.setValue((0, BufferToIP_1.BufferToIPv4)(sipBuffer)); }, encode: () => { const sipStr = this.instance.sip.getValue('0.0.0.0', (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.sip.setValue(sipStr); this.writeBytes(12, (0, IPToBuffer_1.IPv4ToBuffer)(sipStr)); } }, dip: { type: 'string', minLength: 7, maxLength: 15, label: 'Destination Address', contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.IPv4, decode: () => { const dipBuffer = this.readBytes(16, 4); this.instance.dip.setValue((0, BufferToIP_1.BufferToIPv4)(dipBuffer)); }, encode: () => { const dipStr = this.instance.dip.getValue('0.0.0.0', (nodePath) => this.recordError(nodePath, 'Not Found')); this.instance.dip.setValue(dipStr); this.writeBytes(16, (0, IPToBuffer_1.IPv4ToBuffer)(dipStr)); } }, options: { type: 'string', label: 'Options', minLength: 0, maxLength: 40 * 2, contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.HEX, decode: () => { if (this.length < (this.instance.hdrLen.getValue())) { this.instance.options.setValue((0, BufferToHex_1.BufferToHex)(this.readBytes(this.length, (this.instance.hdrLen.getValue()) - this.length))); } }, encode: () => { if (!this.instance.options.isUndefined()) { let optionsBuffer = (0, HexToBuffer_1.HexToBuffer)(this.instance.options.getValue('')); if (optionsBuffer.length > 40) optionsBuffer = optionsBuffer.subarray(0, 40); const estimateHdrLen = this.length + optionsBuffer.length; if (estimateHdrLen % 4) { /** * IPv4 Header should have a length that a multiple of 32 bits * @see https://learningnetwork.cisco.com/s/question/0D53i00000Kt6hHCAR/padding-field-on-ipv4-header */ optionsBuffer = Buffer.concat([optionsBuffer, Buffer.from([0x00])]); } this.writeBytes(this.length, optionsBuffer); } } } } }; this.id = 'ipv4'; this.name = 'Internet Protocol Version 4'; this.nickname = 'IPv4'; } /** * Calculate IPv4 header checksum * @param headerBuffer * @protected */ calculateIPv4Checksum(headerBuffer) { const header = Uint8Array.from(headerBuffer); let sum = 0; for (let i = 0; i < header.length; i += 2) { const word = (header[i] << 8) + (header[i + 1] || 0); sum += word; } while (sum >>> 16) { sum = (sum & 0xFFFF) + (sum >>> 16); } return (~sum) & 0xFFFF; } match() { if (!this.prevCodecModule) return false; return this.prevCodecModule.instance.etherType.getValue() === (0, NumberToHex_1.UInt16ToHex)(0x0800); } } exports.IPv4 = IPv4;