cyberchef 9.37.1 → 9.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +7 -2
  2. package/Gruntfile.js +2 -1
  3. package/package.json +2 -2
  4. package/src/core/Utils.mjs +2 -2
  5. package/src/core/config/Categories.json +1 -0
  6. package/src/core/config/OperationConfig.json +106 -3
  7. package/src/core/config/modules/Default.mjs +2 -0
  8. package/src/core/lib/Binary.mjs +9 -5
  9. package/src/core/lib/Extract.mjs +16 -11
  10. package/src/core/lib/FileSignatures.mjs +12 -12
  11. package/src/core/lib/Protocol.mjs +47 -0
  12. package/src/core/lib/Sort.mjs +105 -0
  13. package/src/core/lib/Stream.mjs +22 -12
  14. package/src/core/operations/ExtractDates.mjs +7 -1
  15. package/src/core/operations/ExtractDomains.mjs +29 -5
  16. package/src/core/operations/ExtractEmailAddresses.mjs +29 -5
  17. package/src/core/operations/ExtractFilePaths.mjs +38 -14
  18. package/src/core/operations/ExtractIPAddresses.mjs +44 -27
  19. package/src/core/operations/ExtractMACAddresses.mjs +28 -6
  20. package/src/core/operations/ExtractURLs.mjs +28 -5
  21. package/src/core/operations/ParseTCP.mjs +245 -0
  22. package/src/core/operations/ParseUDP.mjs +29 -24
  23. package/src/core/operations/Sort.mjs +5 -105
  24. package/src/core/operations/Strings.mjs +36 -14
  25. package/src/core/operations/ToBase45.mjs +1 -1
  26. package/src/core/operations/Unique.mjs +25 -5
  27. package/src/core/operations/index.mjs +2 -0
  28. package/src/node/index.mjs +5 -0
  29. package/src/web/waiters/OperationsWaiter.mjs +5 -1
  30. package/tests/node/tests/operations.mjs +3 -4
  31. package/tests/operations/index.mjs +1 -0
  32. package/tests/operations/tests/ExtractEmailAddresses.mjs +4 -4
  33. package/tests/operations/tests/ParseTCP.mjs +44 -0
  34. package/tests/operations/tests/ParseUDP.mjs +5 -18
@@ -44,7 +44,13 @@ class ExtractDates extends Operation {
44
44
  date3 = "(?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])[- /.](?:19|20)\\d\\d", // mm/dd/yyyy
45
45
  regex = new RegExp(date1 + "|" + date2 + "|" + date3, "ig");
46
46
 
47
- return search(input, regex, null, displayTotal);
47
+ const results = search(input, regex);
48
+
49
+ if (displayTotal) {
50
+ return `Total found: ${results.length}\n\n${results.join("\n")}`;
51
+ } else {
52
+ return results.join("\n");
53
+ }
48
54
  }
49
55
 
50
56
  }
@@ -6,6 +6,7 @@
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
8
  import { search, DOMAIN_REGEX } from "../lib/Extract.mjs";
9
+ import { caseInsensitiveSort } from "../lib/Sort.mjs";
9
10
 
10
11
  /**
11
12
  * Extract domains operation
@@ -25,9 +26,19 @@ class ExtractDomains extends Operation {
25
26
  this.outputType = "string";
26
27
  this.args = [
27
28
  {
28
- "name": "Display total",
29
- "type": "boolean",
30
- "value": true
29
+ name: "Display total",
30
+ type: "boolean",
31
+ value: false
32
+ },
33
+ {
34
+ name: "Sort",
35
+ type: "boolean",
36
+ value: false
37
+ },
38
+ {
39
+ name: "Unique",
40
+ type: "boolean",
41
+ value: false
31
42
  }
32
43
  ];
33
44
  }
@@ -38,8 +49,21 @@ class ExtractDomains extends Operation {
38
49
  * @returns {string}
39
50
  */
40
51
  run(input, args) {
41
- const displayTotal = args[0];
42
- return search(input, DOMAIN_REGEX, null, displayTotal);
52
+ const [displayTotal, sort, unique] = args;
53
+
54
+ const results = search(
55
+ input,
56
+ DOMAIN_REGEX,
57
+ null,
58
+ sort ? caseInsensitiveSort : null,
59
+ unique
60
+ );
61
+
62
+ if (displayTotal) {
63
+ return `Total found: ${results.length}\n\n${results.join("\n")}`;
64
+ } else {
65
+ return results.join("\n");
66
+ }
43
67
  }
44
68
 
45
69
  }
@@ -6,6 +6,7 @@
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
8
  import { search } from "../lib/Extract.mjs";
9
+ import { caseInsensitiveSort } from "../lib/Sort.mjs";
9
10
 
10
11
  /**
11
12
  * Extract email addresses operation
@@ -25,9 +26,19 @@ class ExtractEmailAddresses extends Operation {
25
26
  this.outputType = "string";
26
27
  this.args = [
27
28
  {
28
- "name": "Display total",
29
- "type": "boolean",
30
- "value": false
29
+ name: "Display total",
30
+ type: "boolean",
31
+ value: false
32
+ },
33
+ {
34
+ name: "Sort",
35
+ type: "boolean",
36
+ value: false
37
+ },
38
+ {
39
+ name: "Unique",
40
+ type: "boolean",
41
+ value: false
31
42
  }
32
43
  ];
33
44
  }
@@ -38,10 +49,23 @@ class ExtractEmailAddresses extends Operation {
38
49
  * @returns {string}
39
50
  */
40
51
  run(input, args) {
41
- const displayTotal = args[0],
52
+ const [displayTotal, sort, unique] = args,
42
53
  // email regex from: https://www.regextester.com/98066
43
54
  regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}\])/ig;
44
- return search(input, regex, null, displayTotal);
55
+
56
+ const results = search(
57
+ input,
58
+ regex,
59
+ null,
60
+ sort ? caseInsensitiveSort : null,
61
+ unique
62
+ );
63
+
64
+ if (displayTotal) {
65
+ return `Total found: ${results.length}\n\n${results.join("\n")}`;
66
+ } else {
67
+ return results.join("\n");
68
+ }
45
69
  }
46
70
 
47
71
  }
@@ -6,6 +6,7 @@
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
8
  import { search } from "../lib/Extract.mjs";
9
+ import { caseInsensitiveSort } from "../lib/Sort.mjs";
9
10
 
10
11
  /**
11
12
  * Extract file paths operation
@@ -25,19 +26,29 @@ class ExtractFilePaths extends Operation {
25
26
  this.outputType = "string";
26
27
  this.args = [
27
28
  {
28
- "name": "Windows",
29
- "type": "boolean",
30
- "value": true
29
+ name: "Windows",
30
+ type: "boolean",
31
+ value: true
31
32
  },
32
33
  {
33
- "name": "UNIX",
34
- "type": "boolean",
35
- "value": true
34
+ name: "UNIX",
35
+ type: "boolean",
36
+ value: true
36
37
  },
37
38
  {
38
- "name": "Display total",
39
- "type": "boolean",
40
- "value": false
39
+ name: "Display total",
40
+ type: "boolean",
41
+ value: false
42
+ },
43
+ {
44
+ name: "Sort",
45
+ type: "boolean",
46
+ value: false
47
+ },
48
+ {
49
+ name: "Unique",
50
+ type: "boolean",
51
+ value: false
41
52
  }
42
53
  ];
43
54
  }
@@ -48,7 +59,7 @@ class ExtractFilePaths extends Operation {
48
59
  * @returns {string}
49
60
  */
50
61
  run(input, args) {
51
- const [includeWinPath, includeUnixPath, displayTotal] = args,
62
+ const [includeWinPath, includeUnixPath, displayTotal, sort, unique] = args,
52
63
  winDrive = "[A-Z]:\\\\",
53
64
  winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)~]{0,61}",
54
65
  winExt = "[A-Z\\d]{1,6}",
@@ -65,12 +76,25 @@ class ExtractFilePaths extends Operation {
65
76
  filePaths = unixPath;
66
77
  }
67
78
 
68
- if (filePaths) {
69
- const regex = new RegExp(filePaths, "ig");
70
- return search(input, regex, null, displayTotal);
71
- } else {
79
+ if (!filePaths) {
72
80
  return "";
73
81
  }
82
+
83
+ const regex = new RegExp(filePaths, "ig");
84
+ const results = search(
85
+ input,
86
+ regex,
87
+ null,
88
+ sort ? caseInsensitiveSort : null,
89
+ unique
90
+ );
91
+
92
+ if (displayTotal) {
93
+ return `Total found: ${results.length}\n\n${results.join("\n")}`;
94
+ } else {
95
+ return results.join("\n");
96
+ }
97
+
74
98
  }
75
99
 
76
100
  }
@@ -6,6 +6,7 @@
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
8
  import { search } from "../lib/Extract.mjs";
9
+ import { ipSort } from "../lib/Sort.mjs";
9
10
 
10
11
  /**
11
12
  * Extract IP addresses operation
@@ -25,24 +26,34 @@ class ExtractIPAddresses extends Operation {
25
26
  this.outputType = "string";
26
27
  this.args = [
27
28
  {
28
- "name": "IPv4",
29
- "type": "boolean",
30
- "value": true
29
+ name: "IPv4",
30
+ type: "boolean",
31
+ value: true
31
32
  },
32
33
  {
33
- "name": "IPv6",
34
- "type": "boolean",
35
- "value": false
34
+ name: "IPv6",
35
+ type: "boolean",
36
+ value: false
36
37
  },
37
38
  {
38
- "name": "Remove local IPv4 addresses",
39
- "type": "boolean",
40
- "value": false
39
+ name: "Remove local IPv4 addresses",
40
+ type: "boolean",
41
+ value: false
41
42
  },
42
43
  {
43
- "name": "Display total",
44
- "type": "boolean",
45
- "value": false
44
+ name: "Display total",
45
+ type: "boolean",
46
+ value: false
47
+ },
48
+ {
49
+ name: "Sort",
50
+ type: "boolean",
51
+ value: false
52
+ },
53
+ {
54
+ name: "Unique",
55
+ type: "boolean",
56
+ value: false
46
57
  }
47
58
  ];
48
59
  }
@@ -53,7 +64,7 @@ class ExtractIPAddresses extends Operation {
53
64
  * @returns {string}
54
65
  */
55
66
  run(input, args) {
56
- const [includeIpv4, includeIpv6, removeLocal, displayTotal] = args,
67
+ const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique] = args,
57
68
  ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?",
58
69
  ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})((([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})";
59
70
  let ips = "";
@@ -66,23 +77,29 @@ class ExtractIPAddresses extends Operation {
66
77
  ips = ipv6;
67
78
  }
68
79
 
69
- if (ips) {
70
- const regex = new RegExp(ips, "ig");
80
+ if (!ips) return "";
71
81
 
72
- if (removeLocal) {
73
- const ten = "10\\..+",
74
- oneninetwo = "192\\.168\\..+",
75
- oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
76
- onetwoseven = "127\\..+",
77
- removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
78
- "|" + oneseventwo + "|" + onetwoseven + ")");
82
+ const regex = new RegExp(ips, "ig");
79
83
 
80
- return search(input, regex, removeRegex, displayTotal);
81
- } else {
82
- return search(input, regex, null, displayTotal);
83
- }
84
+ const ten = "10\\..+",
85
+ oneninetwo = "192\\.168\\..+",
86
+ oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
87
+ onetwoseven = "127\\..+",
88
+ removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
89
+ "|" + oneseventwo + "|" + onetwoseven + ")");
90
+
91
+ const results = search(
92
+ input,
93
+ regex,
94
+ removeLocal ? removeRegex : null,
95
+ sort ? ipSort : null,
96
+ unique
97
+ );
98
+
99
+ if (displayTotal) {
100
+ return `Total found: ${results.length}\n\n${results.join("\n")}`;
84
101
  } else {
85
- return "";
102
+ return results.join("\n");
86
103
  }
87
104
  }
88
105
 
@@ -6,6 +6,7 @@
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
8
  import { search } from "../lib/Extract.mjs";
9
+ import { hexadecimalSort } from "../lib/Sort.mjs";
9
10
 
10
11
  /**
11
12
  * Extract MAC addresses operation
@@ -25,9 +26,19 @@ class ExtractMACAddresses extends Operation {
25
26
  this.outputType = "string";
26
27
  this.args = [
27
28
  {
28
- "name": "Display total",
29
- "type": "boolean",
30
- "value": false
29
+ name: "Display total",
30
+ type: "boolean",
31
+ value: false
32
+ },
33
+ {
34
+ name: "Sort",
35
+ type: "boolean",
36
+ value: false
37
+ },
38
+ {
39
+ name: "Unique",
40
+ type: "boolean",
41
+ value: false
31
42
  }
32
43
  ];
33
44
  }
@@ -38,10 +49,21 @@ class ExtractMACAddresses extends Operation {
38
49
  * @returns {string}
39
50
  */
40
51
  run(input, args) {
41
- const displayTotal = args[0],
42
- regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig;
52
+ const [displayTotal, sort, unique] = args,
53
+ regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig,
54
+ results = search(
55
+ input,
56
+ regex,
57
+ null,
58
+ sort ? hexadecimalSort : null,
59
+ unique
60
+ );
43
61
 
44
- return search(input, regex, null, displayTotal);
62
+ if (displayTotal) {
63
+ return `Total found: ${results.length}\n\n${results.join("\n")}`;
64
+ } else {
65
+ return results.join("\n");
66
+ }
45
67
  }
46
68
 
47
69
  }
@@ -6,6 +6,7 @@
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
8
  import { search, URL_REGEX } from "../lib/Extract.mjs";
9
+ import { caseInsensitiveSort } from "../lib/Sort.mjs";
9
10
 
10
11
  /**
11
12
  * Extract URLs operation
@@ -25,9 +26,19 @@ class ExtractURLs extends Operation {
25
26
  this.outputType = "string";
26
27
  this.args = [
27
28
  {
28
- "name": "Display total",
29
- "type": "boolean",
30
- "value": false
29
+ name: "Display total",
30
+ type: "boolean",
31
+ value: false
32
+ },
33
+ {
34
+ name: "Sort",
35
+ type: "boolean",
36
+ value: false
37
+ },
38
+ {
39
+ name: "Unique",
40
+ type: "boolean",
41
+ value: false
31
42
  }
32
43
  ];
33
44
  }
@@ -38,8 +49,20 @@ class ExtractURLs extends Operation {
38
49
  * @returns {string}
39
50
  */
40
51
  run(input, args) {
41
- const displayTotal = args[0];
42
- return search(input, URL_REGEX, null, displayTotal);
52
+ const [displayTotal, sort, unique] = args;
53
+ const results = search(
54
+ input,
55
+ URL_REGEX,
56
+ null,
57
+ sort ? caseInsensitiveSort : null,
58
+ unique
59
+ );
60
+
61
+ if (displayTotal) {
62
+ return `Total found: ${results.length}\n\n${results.join("\n")}`;
63
+ } else {
64
+ return results.join("\n");
65
+ }
43
66
  }
44
67
 
45
68
  }
@@ -0,0 +1,245 @@
1
+ /**
2
+ * @author n1474335 [n1474335@gmail.com]
3
+ * @copyright Crown Copyright 2022
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import Stream from "../lib/Stream.mjs";
9
+ import {toHexFast, fromHex} from "../lib/Hex.mjs";
10
+ import {toBinary} from "../lib/Binary.mjs";
11
+ import {objToTable, bytesToLargeNumber} from "../lib/Protocol.mjs";
12
+ import Utils from "../Utils.mjs";
13
+ import OperationError from "../errors/OperationError.mjs";
14
+ import BigNumber from "bignumber.js";
15
+
16
+ /**
17
+ * Parse TCP operation
18
+ */
19
+ class ParseTCP extends Operation {
20
+
21
+ /**
22
+ * ParseTCP constructor
23
+ */
24
+ constructor() {
25
+ super();
26
+
27
+ this.name = "Parse TCP";
28
+ this.module = "Default";
29
+ this.description = "Parses a TCP header and payload (if present).";
30
+ this.infoURL = "https://wikipedia.org/wiki/Transmission_Control_Protocol";
31
+ this.inputType = "string";
32
+ this.outputType = "json";
33
+ this.presentType = "html";
34
+ this.args = [
35
+ {
36
+ name: "Input format",
37
+ type: "option",
38
+ value: ["Hex", "Raw"]
39
+ }
40
+ ];
41
+ }
42
+
43
+ /**
44
+ * @param {string} input
45
+ * @param {Object[]} args
46
+ * @returns {html}
47
+ */
48
+ run(input, args) {
49
+ const format = args[0];
50
+
51
+ if (format === "Hex") {
52
+ input = fromHex(input);
53
+ } else if (format === "Raw") {
54
+ input = Utils.strToArrayBuffer(input);
55
+ } else {
56
+ throw new OperationError("Unrecognised input format.");
57
+ }
58
+
59
+ const s = new Stream(new Uint8Array(input));
60
+ if (s.length < 20) {
61
+ throw new OperationError("Need at least 20 bytes for a TCP Header");
62
+ }
63
+
64
+ // Parse Header
65
+ const TCPPacket = {
66
+ "Source port": s.readInt(2),
67
+ "Destination port": s.readInt(2),
68
+ "Sequence number": bytesToLargeNumber(s.getBytes(4)),
69
+ "Acknowledgement number": s.readInt(4),
70
+ "Data offset": s.readBits(4),
71
+ "Flags": {
72
+ "Reserved": toBinary(s.readBits(3), "", 3),
73
+ "NS": s.readBits(1),
74
+ "CWR": s.readBits(1),
75
+ "ECE": s.readBits(1),
76
+ "URG": s.readBits(1),
77
+ "ACK": s.readBits(1),
78
+ "PSH": s.readBits(1),
79
+ "RST": s.readBits(1),
80
+ "SYN": s.readBits(1),
81
+ "FIN": s.readBits(1),
82
+ },
83
+ "Window size": s.readInt(2),
84
+ "Checksum": "0x" + toHexFast(s.getBytes(2)),
85
+ "Urgent pointer": "0x" + toHexFast(s.getBytes(2))
86
+ };
87
+
88
+ // Parse options if present
89
+ let windowScaleShift = 0;
90
+ if (TCPPacket["Data offset"] > 5) {
91
+ let remainingLength = TCPPacket["Data offset"] * 4 - 20;
92
+
93
+ const options = {};
94
+ while (remainingLength > 0) {
95
+ const option = {
96
+ "Kind": s.readInt(1)
97
+ };
98
+
99
+ let opt = { name: "Reserved", length: true };
100
+ if (Object.prototype.hasOwnProperty.call(TCP_OPTION_KIND_LOOKUP, option.Kind)) {
101
+ opt = TCP_OPTION_KIND_LOOKUP[option.Kind];
102
+ }
103
+
104
+ // Add Length and Value fields
105
+ if (opt.length) {
106
+ option.Length = s.readInt(1);
107
+
108
+ if (option.Length > 2) {
109
+ if (Object.prototype.hasOwnProperty.call(opt, "parser")) {
110
+ option.Value = opt.parser(s.getBytes(option.Length - 2));
111
+ } else {
112
+ option.Value = option.Length <= 6 ?
113
+ s.readInt(option.Length - 2):
114
+ "0x" + toHexFast(s.getBytes(option.Length - 2));
115
+ }
116
+
117
+ // Store Window Scale shift for later
118
+ if (option.Kind === 3 && option.Value) {
119
+ windowScaleShift = option.Value["Shift count"];
120
+ }
121
+ }
122
+ }
123
+ options[opt.name] = option;
124
+
125
+ const length = option.Length || 1;
126
+ remainingLength -= length;
127
+ }
128
+ TCPPacket.Options = options;
129
+ }
130
+
131
+ if (s.hasMore()) {
132
+ TCPPacket.Data = "0x" + toHexFast(s.getBytes());
133
+ }
134
+
135
+ // Improve values
136
+ TCPPacket["Data offset"] = `${TCPPacket["Data offset"]} (${TCPPacket["Data offset"] * 4} bytes)`;
137
+ const trueWndSize = BigNumber(TCPPacket["Window size"]).multipliedBy(BigNumber(2).pow(BigNumber(windowScaleShift)));
138
+ TCPPacket["Window size"] = `${TCPPacket["Window size"]} (Scaled: ${trueWndSize})`;
139
+
140
+ return TCPPacket;
141
+ }
142
+
143
+ /**
144
+ * Displays the TCP Packet in a tabular style
145
+ * @param {Object} data
146
+ * @returns {html}
147
+ */
148
+ present(data) {
149
+ return objToTable(data);
150
+ }
151
+
152
+ }
153
+
154
+ // Taken from https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml
155
+ // on 2022-05-30
156
+ const TCP_OPTION_KIND_LOOKUP = {
157
+ 0: { name: "End of Option List", length: false },
158
+ 1: { name: "No-Operation", length: false },
159
+ 2: { name: "Maximum Segment Size", length: true },
160
+ 3: { name: "Window Scale", length: true, parser: windowScaleParser },
161
+ 4: { name: "SACK Permitted", length: true },
162
+ 5: { name: "SACK", length: true },
163
+ 6: { name: "Echo (obsoleted by option 8)", length: true },
164
+ 7: { name: "Echo Reply (obsoleted by option 8)", length: true },
165
+ 8: { name: "Timestamps", length: true, parser: tcpTimestampParser },
166
+ 9: { name: "Partial Order Connection Permitted (obsolete)", length: true },
167
+ 10: { name: "Partial Order Service Profile (obsolete)", length: true },
168
+ 11: { name: "CC (obsolete)", length: true },
169
+ 12: { name: "CC.NEW (obsolete)", length: true },
170
+ 13: { name: "CC.ECHO (obsolete)", length: true },
171
+ 14: { name: "TCP Alternate Checksum Request (obsolete)", length: true, parser: tcpAlternateChecksumParser },
172
+ 15: { name: "TCP Alternate Checksum Data (obsolete)", length: true },
173
+ 16: { name: "Skeeter", length: true },
174
+ 17: { name: "Bubba", length: true },
175
+ 18: { name: "Trailer Checksum Option", length: true },
176
+ 19: { name: "MD5 Signature Option (obsoleted by option 29)", length: true },
177
+ 20: { name: "SCPS Capabilities", length: true },
178
+ 21: { name: "Selective Negative Acknowledgements", length: true },
179
+ 22: { name: "Record Boundaries", length: true },
180
+ 23: { name: "Corruption experienced", length: true },
181
+ 24: { name: "SNAP", length: true },
182
+ 25: { name: "Unassigned (released 2000-12-18)", length: true },
183
+ 26: { name: "TCP Compression Filter", length: true },
184
+ 27: { name: "Quick-Start Response", length: true },
185
+ 28: { name: "User Timeout Option (also, other known unauthorized use)", length: true },
186
+ 29: { name: "TCP Authentication Option (TCP-AO)", length: true },
187
+ 30: { name: "Multipath TCP (MPTCP)", length: true },
188
+ 69: { name: "Encryption Negotiation (TCP-ENO)", length: true },
189
+ 70: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
190
+ 76: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
191
+ 77: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
192
+ 78: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
193
+ 253: { name: "RFC3692-style Experiment 1 (also improperly used for shipping products) ", length: true },
194
+ 254: { name: "RFC3692-style Experiment 2 (also improperly used for shipping products) ", length: true }
195
+ };
196
+
197
+ /**
198
+ * Parses the TCP Alternate Checksum Request field
199
+ * @param {Uint8Array} data
200
+ */
201
+ function tcpAlternateChecksumParser(data) {
202
+ const lookup = {
203
+ 0: "TCP Checksum",
204
+ 1: "8-bit Fletchers's algorithm",
205
+ 2: "16-bit Fletchers's algorithm",
206
+ 3: "Redundant Checksum Avoidance"
207
+ }[data[0]];
208
+
209
+ return `${lookup} (0x${toHexFast(data)})`;
210
+ }
211
+
212
+ /**
213
+ * Parses the TCP Timestamp field
214
+ * @param {Uint8Array} data
215
+ */
216
+ function tcpTimestampParser(data) {
217
+ const s = new Stream(data);
218
+
219
+ if (s.length !== 8)
220
+ return `Error: Timestamp field should be 8 bytes long (received 0x${toHexFast(data)})`;
221
+
222
+ const tsval = bytesToLargeNumber(s.getBytes(4)),
223
+ tsecr = bytesToLargeNumber(s.getBytes(4));
224
+
225
+ return {
226
+ "Current Timestamp": tsval,
227
+ "Echo Reply": tsecr
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Parses the Window Scale field
233
+ * @param {Uint8Array} data
234
+ */
235
+ function windowScaleParser(data) {
236
+ if (data.length !== 1)
237
+ return `Error: Window Scale should be one byte long (received 0x${toHexFast(data)})`;
238
+
239
+ return {
240
+ "Shift count": data[0],
241
+ "Multiplier": 1 << data[0]
242
+ };
243
+ }
244
+
245
+ export default ParseTCP;