diff --git a/src/core/operations/ParseIPv4Header.mjs b/src/core/operations/ParseIPv4Header.mjs new file mode 100644 index 00000000..d88d6f60 --- /dev/null +++ b/src/core/operations/ParseIPv4Header.mjs @@ -0,0 +1,127 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import Utils from "../Utils"; +import {fromHex, toHex} from "../lib/Hex"; +import {_ipv4ToStr, _protocolLookup, calculateTCPIPChecksum} from "../lib/Ip"; + +/** + * Parse IPv4 header operation + */ +class ParseIPv4Header extends Operation { + + /** + * ParseIPv4Header constructor + */ + constructor() { + super(); + + this.name = "Parse IPv4 header"; + this.module = "JSBN"; + this.description = "Given an IPv4 header, this operations parses and displays each field in an easily readable format."; + this.inputType = "string"; + this.outputType = "html"; + this.args = [ + { + "name": "Input format", + "type": "option", + "value": ["Hex", "Raw"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {html} + */ + run(input, args) { + const format = args[0]; + let output; + + if (format === "Hex") { + input = fromHex(input); + } else if (format === "Raw") { + input = Utils.strToByteArray(input); + } else { + return "Unrecognised input format."; + } + + let ihl = input[0] & 0x0f; + const dscp = (input[1] >>> 2) & 0x3f, + ecn = input[1] & 0x03, + length = input[2] << 8 | input[3], + identification = input[4] << 8 | input[5], + flags = (input[6] >>> 5) & 0x07, + fragOffset = (input[6] & 0x1f) << 8 | input[7], + ttl = input[8], + protocol = input[9], + checksum = input[10] << 8 | input[11], + srcIP = input[12] << 24 | input[13] << 16 | input[14] << 8 | input[15], + dstIP = input[16] << 24 | input[17] << 16 | input[18] << 8 | input[19], + checksumHeader = input.slice(0, 10).concat([0, 0]).concat(input.slice(12, 20)); + let version = (input[0] >>> 4) & 0x0f, + options = []; + + + // Version + if (version !== 4) { + version = version + " (Error: for IPv4 headers, this should always be set to 4)"; + } + + // IHL + if (ihl < 5) { + ihl = ihl + " (Error: this should always be at least 5)"; + } else if (ihl > 5) { + // sort out options... + const optionsLen = ihl * 4 - 20; + options = input.slice(20, optionsLen + 20); + } + + // Protocol + const protocolInfo = _protocolLookup[protocol] || {keyword: "", protocol: ""}; + + // Checksum + const correctChecksum = calculateTCPIPChecksum(checksumHeader), + givenChecksum = Utils.hex(checksum); + let checksumResult; + if (correctChecksum === givenChecksum) { + checksumResult = givenChecksum + " (correct)"; + } else { + checksumResult = givenChecksum + " (incorrect, should be " + correctChecksum + ")"; + } + + output = "
Field | Value |
---|---|
Version | " + version + " |
Internet Header Length (IHL) | " + ihl + " (" + (ihl * 4) + " bytes) |
Differentiated Services Code Point (DSCP) | " + dscp + " |
Explicit Congestion Notification (ECN) | " + ecn + " |
Total length | " + length + " bytes" + + "\n IP header: " + (ihl * 4) + " bytes" + + "\n Data: " + (length - ihl * 4) + " bytes |
Identification | 0x" + Utils.hex(identification) + " (" + identification + ") |
Flags | 0x" + Utils.hex(flags, 2) + + "\n Reserved bit:" + (flags >> 2) + " (must be 0)" + + "\n Don't fragment:" + (flags >> 1 & 1) + + "\n More fragments:" + (flags & 1) + " |
Fragment offset | " + fragOffset + " |
Time-To-Live | " + ttl + " |
Protocol | " + protocol + ", " + protocolInfo.protocol + " (" + protocolInfo.keyword + ") |
Header checksum | " + checksumResult + " |
Source IP address | " + _ipv4ToStr(srcIP) + " |
Destination IP address | " + _ipv4ToStr(dstIP) + " |
Options | " + toHex(options) + " |