cyberchef 9.37.3 → 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.
- package/CHANGELOG.md +7 -2
- package/Gruntfile.js +2 -1
- package/package.json +2 -2
- package/src/core/config/Categories.json +1 -0
- package/src/core/config/OperationConfig.json +30 -2
- package/src/core/config/modules/Default.mjs +2 -0
- package/src/core/lib/Binary.mjs +9 -5
- package/src/core/lib/FileSignatures.mjs +12 -12
- package/src/core/lib/Protocol.mjs +47 -0
- package/src/core/lib/Stream.mjs +22 -12
- package/src/core/operations/ParseTCP.mjs +245 -0
- package/src/core/operations/ParseUDP.mjs +29 -24
- package/src/core/operations/index.mjs +2 -0
- package/src/node/index.mjs +5 -0
- package/src/web/waiters/OperationsWaiter.mjs +5 -1
- package/tests/operations/index.mjs +1 -0
- package/tests/operations/tests/ParseTCP.mjs +44 -0
- package/tests/operations/tests/ParseUDP.mjs +5 -18
package/CHANGELOG.md
CHANGED
|
@@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of
|
|
|
13
13
|
|
|
14
14
|
## Details
|
|
15
15
|
|
|
16
|
+
### [9.38.0] - 2022-05-30
|
|
17
|
+
- Added 'Parse TCP' operation [@n1474335] | [a895d1d]
|
|
18
|
+
|
|
16
19
|
### [9.37.0] - 2022-03-29
|
|
17
20
|
- 'SM4 Encrypt' and 'SM4 Decrypt' operations added [@swesven] | [#1189]
|
|
18
21
|
- NoPadding options added for CBC and ECB modes in AES, DES and Triple DES Decrypt operations [@swesven] | [#1189]
|
|
@@ -135,7 +138,7 @@ All major and minor version changes will be documented in this file. Details of
|
|
|
135
138
|
|
|
136
139
|
<details>
|
|
137
140
|
<summary>Click to expand v8 minor versions</summary>
|
|
138
|
-
|
|
141
|
+
|
|
139
142
|
### [8.38.0] - 2019-07-03
|
|
140
143
|
- 'Streebog' and 'GOST hash' operations added [@MShwed] [@n1474335] | [#530]
|
|
141
144
|
|
|
@@ -288,6 +291,7 @@ All major and minor version changes will be documented in this file. Details of
|
|
|
288
291
|
|
|
289
292
|
|
|
290
293
|
|
|
294
|
+
[9.38.0]: https://github.com/gchq/CyberChef/releases/tag/v9.38.0
|
|
291
295
|
[9.37.0]: https://github.com/gchq/CyberChef/releases/tag/v9.37.0
|
|
292
296
|
[9.36.0]: https://github.com/gchq/CyberChef/releases/tag/v9.36.0
|
|
293
297
|
[9.35.0]: https://github.com/gchq/CyberChef/releases/tag/v9.35.0
|
|
@@ -416,6 +420,7 @@ All major and minor version changes will be documented in this file. Details of
|
|
|
416
420
|
[289a417]: https://github.com/gchq/CyberChef/commit/289a417dfb5923de5e1694354ec42a08d9395bfe
|
|
417
421
|
[e9ca4dc]: https://github.com/gchq/CyberChef/commit/e9ca4dc9caf98f33fd986431cd400c88082a42b8
|
|
418
422
|
[dd18e52]: https://github.com/gchq/CyberChef/commit/dd18e529939078b89867297b181a584e8b2cc7da
|
|
423
|
+
[a895d1d]: https://github.com/gchq/CyberChef/commit/a895d1d82a2f92d440a0c5eca2bc7c898107b737
|
|
419
424
|
|
|
420
425
|
[#95]: https://github.com/gchq/CyberChef/pull/299
|
|
421
426
|
[#173]: https://github.com/gchq/CyberChef/pull/173
|
|
@@ -502,4 +507,4 @@ All major and minor version changes will be documented in this file. Details of
|
|
|
502
507
|
[#1242]: https://github.com/gchq/CyberChef/pull/1242
|
|
503
508
|
[#1244]: https://github.com/gchq/CyberChef/pull/1244
|
|
504
509
|
[#1313]: https://github.com/gchq/CyberChef/pull/1313
|
|
505
|
-
[#1326]: https://github.com/gchq/CyberChef/pull/1326
|
|
510
|
+
[#1326]: https://github.com/gchq/CyberChef/pull/1326
|
package/Gruntfile.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cyberchef",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.38.0",
|
|
4
4
|
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
|
5
5
|
"author": "n1474335 <n1474335@gmail.com>",
|
|
6
6
|
"homepage": "https://gchq.github.io/CyberChef",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"autoprefixer": "^10.4.4",
|
|
49
49
|
"babel-loader": "^8.2.4",
|
|
50
50
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
51
|
-
"chromedriver": "^
|
|
51
|
+
"chromedriver": "^101.0.0",
|
|
52
52
|
"cli-progress": "^3.10.0",
|
|
53
53
|
"colors": "^1.4.0",
|
|
54
54
|
"copy-webpack-plugin": "^10.2.4",
|
|
@@ -9518,6 +9518,25 @@
|
|
|
9518
9518
|
}
|
|
9519
9519
|
]
|
|
9520
9520
|
},
|
|
9521
|
+
"Parse TCP": {
|
|
9522
|
+
"module": "Default",
|
|
9523
|
+
"description": "Parses a TCP header and payload (if present).",
|
|
9524
|
+
"infoURL": "https://wikipedia.org/wiki/Transmission_Control_Protocol",
|
|
9525
|
+
"inputType": "string",
|
|
9526
|
+
"outputType": "html",
|
|
9527
|
+
"flowControl": false,
|
|
9528
|
+
"manualBake": false,
|
|
9529
|
+
"args": [
|
|
9530
|
+
{
|
|
9531
|
+
"name": "Input format",
|
|
9532
|
+
"type": "option",
|
|
9533
|
+
"value": [
|
|
9534
|
+
"Hex",
|
|
9535
|
+
"Raw"
|
|
9536
|
+
]
|
|
9537
|
+
}
|
|
9538
|
+
]
|
|
9539
|
+
},
|
|
9521
9540
|
"Parse TLV": {
|
|
9522
9541
|
"module": "Default",
|
|
9523
9542
|
"description": "Converts a Type-Length-Value (TLV) encoded string into a JSON object. Can optionally include a <code>Key</code> / <code>Type</code> entry. <br><br>Tags: Key-Length-Value, KLV, Length-Value, LV",
|
|
@@ -9548,11 +9567,20 @@
|
|
|
9548
9567
|
"module": "Default",
|
|
9549
9568
|
"description": "Parses a UDP header and payload (if present).",
|
|
9550
9569
|
"infoURL": "https://wikipedia.org/wiki/User_Datagram_Protocol",
|
|
9551
|
-
"inputType": "
|
|
9570
|
+
"inputType": "string",
|
|
9552
9571
|
"outputType": "html",
|
|
9553
9572
|
"flowControl": false,
|
|
9554
9573
|
"manualBake": false,
|
|
9555
|
-
"args": [
|
|
9574
|
+
"args": [
|
|
9575
|
+
{
|
|
9576
|
+
"name": "Input format",
|
|
9577
|
+
"type": "option",
|
|
9578
|
+
"value": [
|
|
9579
|
+
"Hex",
|
|
9580
|
+
"Raw"
|
|
9581
|
+
]
|
|
9582
|
+
}
|
|
9583
|
+
]
|
|
9556
9584
|
},
|
|
9557
9585
|
"Parse UNIX file permissions": {
|
|
9558
9586
|
"module": "Default",
|
|
@@ -97,6 +97,7 @@ import ParseIPRange from "../../operations/ParseIPRange.mjs";
|
|
|
97
97
|
import ParseIPv4Header from "../../operations/ParseIPv4Header.mjs";
|
|
98
98
|
import ParseIPv6Address from "../../operations/ParseIPv6Address.mjs";
|
|
99
99
|
import ParseSSHHostKey from "../../operations/ParseSSHHostKey.mjs";
|
|
100
|
+
import ParseTCP from "../../operations/ParseTCP.mjs";
|
|
100
101
|
import ParseTLV from "../../operations/ParseTLV.mjs";
|
|
101
102
|
import ParseUDP from "../../operations/ParseUDP.mjs";
|
|
102
103
|
import ParseUNIXFilePermissions from "../../operations/ParseUNIXFilePermissions.mjs";
|
|
@@ -263,6 +264,7 @@ OpModules.Default = {
|
|
|
263
264
|
"Parse IPv4 header": ParseIPv4Header,
|
|
264
265
|
"Parse IPv6 address": ParseIPv6Address,
|
|
265
266
|
"Parse SSH Host Key": ParseSSHHostKey,
|
|
267
|
+
"Parse TCP": ParseTCP,
|
|
266
268
|
"Parse TLV": ParseTLV,
|
|
267
269
|
"Parse UDP": ParseUDP,
|
|
268
270
|
"Parse UNIX file permissions": ParseUNIXFilePermissions,
|
package/src/core/lib/Binary.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
13
13
|
/**
|
|
14
14
|
* Convert a byte array into a binary string.
|
|
15
15
|
*
|
|
16
|
-
* @param {Uint8Array|byteArray} data
|
|
16
|
+
* @param {Uint8Array|byteArray|number} data
|
|
17
17
|
* @param {string} [delim="Space"]
|
|
18
18
|
* @param {number} [padding=8]
|
|
19
19
|
* @returns {string}
|
|
@@ -26,13 +26,17 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
26
26
|
* toBinary([10,20,30], ":");
|
|
27
27
|
*/
|
|
28
28
|
export function toBinary(data, delim="Space", padding=8) {
|
|
29
|
-
if (!data) return "";
|
|
30
|
-
|
|
31
29
|
delim = Utils.charRep(delim);
|
|
32
30
|
let output = "";
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
if (data.length) { // array
|
|
33
|
+
for (let i = 0; i < data.length; i++) {
|
|
34
|
+
output += data[i].toString(2).padStart(padding, "0") + delim;
|
|
35
|
+
}
|
|
36
|
+
} else if (typeof data === "number") { // Single value
|
|
37
|
+
return data.toString(2).padStart(padding, "0");
|
|
38
|
+
} else {
|
|
39
|
+
return "";
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
if (delim.length) {
|
|
@@ -3778,8 +3778,8 @@ function parseDEFLATE(stream) {
|
|
|
3778
3778
|
|
|
3779
3779
|
while (!finalBlock) {
|
|
3780
3780
|
// Read header
|
|
3781
|
-
finalBlock = stream.readBits(1);
|
|
3782
|
-
const blockType = stream.readBits(2);
|
|
3781
|
+
finalBlock = stream.readBits(1, "le");
|
|
3782
|
+
const blockType = stream.readBits(2, "le");
|
|
3783
3783
|
|
|
3784
3784
|
if (blockType === 0) {
|
|
3785
3785
|
/* No compression */
|
|
@@ -3798,16 +3798,16 @@ function parseDEFLATE(stream) {
|
|
|
3798
3798
|
/* Dynamic Huffman */
|
|
3799
3799
|
|
|
3800
3800
|
// Read the number of liternal and length codes
|
|
3801
|
-
const hlit = stream.readBits(5) + 257;
|
|
3801
|
+
const hlit = stream.readBits(5, "le") + 257;
|
|
3802
3802
|
// Read the number of distance codes
|
|
3803
|
-
const hdist = stream.readBits(5) + 1;
|
|
3803
|
+
const hdist = stream.readBits(5, "le") + 1;
|
|
3804
3804
|
// Read the number of code lengths
|
|
3805
|
-
const hclen = stream.readBits(4) + 4;
|
|
3805
|
+
const hclen = stream.readBits(4, "le") + 4;
|
|
3806
3806
|
|
|
3807
3807
|
// Parse code lengths
|
|
3808
3808
|
const codeLengths = new Uint8Array(huffmanOrder.length);
|
|
3809
3809
|
for (let i = 0; i < hclen; i++) {
|
|
3810
|
-
codeLengths[huffmanOrder[i]] = stream.readBits(3);
|
|
3810
|
+
codeLengths[huffmanOrder[i]] = stream.readBits(3, "le");
|
|
3811
3811
|
}
|
|
3812
3812
|
|
|
3813
3813
|
// Parse length table
|
|
@@ -3819,16 +3819,16 @@ function parseDEFLATE(stream) {
|
|
|
3819
3819
|
code = readHuffmanCode(stream, codeLengthsTable);
|
|
3820
3820
|
switch (code) {
|
|
3821
3821
|
case 16:
|
|
3822
|
-
repeat = 3 + stream.readBits(2);
|
|
3822
|
+
repeat = 3 + stream.readBits(2, "le");
|
|
3823
3823
|
while (repeat--) lengthTable[i++] = prev;
|
|
3824
3824
|
break;
|
|
3825
3825
|
case 17:
|
|
3826
|
-
repeat = 3 + stream.readBits(3);
|
|
3826
|
+
repeat = 3 + stream.readBits(3, "le");
|
|
3827
3827
|
while (repeat--) lengthTable[i++] = 0;
|
|
3828
3828
|
prev = 0;
|
|
3829
3829
|
break;
|
|
3830
3830
|
case 18:
|
|
3831
|
-
repeat = 11 + stream.readBits(7);
|
|
3831
|
+
repeat = 11 + stream.readBits(7, "le");
|
|
3832
3832
|
while (repeat--) lengthTable[i++] = 0;
|
|
3833
3833
|
prev = 0;
|
|
3834
3834
|
break;
|
|
@@ -3886,11 +3886,11 @@ function parseHuffmanBlock(stream, litTab, distTab) {
|
|
|
3886
3886
|
if (code < 256) continue;
|
|
3887
3887
|
|
|
3888
3888
|
// Length code
|
|
3889
|
-
stream.readBits(lengthExtraTable[code - 257]);
|
|
3889
|
+
stream.readBits(lengthExtraTable[code - 257], "le");
|
|
3890
3890
|
|
|
3891
3891
|
// Dist code
|
|
3892
3892
|
code = readHuffmanCode(stream, distTab);
|
|
3893
|
-
stream.readBits(distanceExtraTable[code]);
|
|
3893
|
+
stream.readBits(distanceExtraTable[code], "le");
|
|
3894
3894
|
}
|
|
3895
3895
|
}
|
|
3896
3896
|
|
|
@@ -3948,7 +3948,7 @@ function readHuffmanCode(stream, table) {
|
|
|
3948
3948
|
const [codeTable, maxCodeLength] = table;
|
|
3949
3949
|
|
|
3950
3950
|
// Read max length
|
|
3951
|
-
const bitsBuf = stream.readBits(maxCodeLength);
|
|
3951
|
+
const bitsBuf = stream.readBits(maxCodeLength, "le");
|
|
3952
3952
|
const codeWithLength = codeTable[bitsBuf & ((1 << maxCodeLength) - 1)];
|
|
3953
3953
|
const codeLength = codeWithLength >>> 16;
|
|
3954
3954
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol parsing functions.
|
|
3
|
+
*
|
|
4
|
+
* @author n1474335 [n1474335@gmail.com]
|
|
5
|
+
* @copyright Crown Copyright 2022
|
|
6
|
+
* @license Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import BigNumber from "bignumber.js";
|
|
10
|
+
import {toHexFast} from "../lib/Hex.mjs";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Recursively displays a JSON object as an HTML table
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} obj
|
|
16
|
+
* @returns string
|
|
17
|
+
*/
|
|
18
|
+
export function objToTable(obj, nested=false) {
|
|
19
|
+
let html = `<table
|
|
20
|
+
class='table table-sm table-nonfluid ${nested ? "mb-0 table-borderless" : "table-bordered"}'
|
|
21
|
+
style='table-layout: fixed; ${nested ? "margin: -1px !important;" : ""}'>`;
|
|
22
|
+
if (!nested)
|
|
23
|
+
html += `<tr>
|
|
24
|
+
<th>Field</th>
|
|
25
|
+
<th>Value</th>
|
|
26
|
+
</tr>`;
|
|
27
|
+
|
|
28
|
+
for (const key in obj) {
|
|
29
|
+
html += `<tr><td style='word-wrap: break-word'>${key}</td>`;
|
|
30
|
+
if (typeof obj[key] === "object")
|
|
31
|
+
html += `<td style='padding: 0'>${objToTable(obj[key], true)}</td>`;
|
|
32
|
+
else
|
|
33
|
+
html += `<td>${obj[key]}</td>`;
|
|
34
|
+
html += "</tr>";
|
|
35
|
+
}
|
|
36
|
+
html += "</table>";
|
|
37
|
+
return html;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Converts bytes into a BigNumber string
|
|
42
|
+
* @param {Uint8Array} bs
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
export function bytesToLargeNumber(bs) {
|
|
46
|
+
return BigNumber(toHexFast(bs), 16).toString();
|
|
47
|
+
}
|
package/src/core/lib/Stream.mjs
CHANGED
|
@@ -27,15 +27,17 @@ export default class Stream {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Get a number of bytes from the current position.
|
|
30
|
+
* Get a number of bytes from the current position, or all remaining bytes.
|
|
31
31
|
*
|
|
32
|
-
* @param {number} numBytes
|
|
32
|
+
* @param {number} [numBytes=null]
|
|
33
33
|
* @returns {Uint8Array}
|
|
34
34
|
*/
|
|
35
|
-
getBytes(numBytes) {
|
|
35
|
+
getBytes(numBytes=null) {
|
|
36
36
|
if (this.position > this.length) return undefined;
|
|
37
37
|
|
|
38
|
-
const newPosition =
|
|
38
|
+
const newPosition = numBytes !== null ?
|
|
39
|
+
this.position + numBytes :
|
|
40
|
+
this.length;
|
|
39
41
|
const bytes = this.bytes.slice(this.position, newPosition);
|
|
40
42
|
this.position = newPosition;
|
|
41
43
|
this.bitPos = 0;
|
|
@@ -91,34 +93,40 @@ export default class Stream {
|
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
/**
|
|
94
|
-
* Reads a number of bits from the buffer.
|
|
95
|
-
*
|
|
96
|
-
* @TODO Add endianness
|
|
96
|
+
* Reads a number of bits from the buffer in big or little endian.
|
|
97
97
|
*
|
|
98
98
|
* @param {number} numBits
|
|
99
|
+
* @param {string} [endianness="be"]
|
|
99
100
|
* @returns {number}
|
|
100
101
|
*/
|
|
101
|
-
readBits(numBits) {
|
|
102
|
+
readBits(numBits, endianness="be") {
|
|
102
103
|
if (this.position > this.length) return undefined;
|
|
103
104
|
|
|
104
105
|
let bitBuf = 0,
|
|
105
106
|
bitBufLen = 0;
|
|
106
107
|
|
|
107
108
|
// Add remaining bits from current byte
|
|
108
|
-
bitBuf =
|
|
109
|
+
bitBuf = this.bytes[this.position++] & bitMask(this.bitPos);
|
|
110
|
+
if (endianness !== "be") bitBuf >>>= this.bitPos;
|
|
109
111
|
bitBufLen = 8 - this.bitPos;
|
|
110
112
|
this.bitPos = 0;
|
|
111
113
|
|
|
112
114
|
// Not enough bits yet
|
|
113
115
|
while (bitBufLen < numBits) {
|
|
114
|
-
|
|
116
|
+
if (endianness === "be")
|
|
117
|
+
bitBuf = (bitBuf << bitBufLen) | this.bytes[this.position++];
|
|
118
|
+
else
|
|
119
|
+
bitBuf |= this.bytes[this.position++] << bitBufLen;
|
|
115
120
|
bitBufLen += 8;
|
|
116
121
|
}
|
|
117
122
|
|
|
118
123
|
// Reverse back to numBits
|
|
119
124
|
if (bitBufLen > numBits) {
|
|
120
125
|
const excess = bitBufLen - numBits;
|
|
121
|
-
|
|
126
|
+
if (endianness === "be")
|
|
127
|
+
bitBuf >>>= excess;
|
|
128
|
+
else
|
|
129
|
+
bitBuf &= (1 << numBits) - 1;
|
|
122
130
|
bitBufLen -= excess;
|
|
123
131
|
this.position--;
|
|
124
132
|
this.bitPos = 8 - excess;
|
|
@@ -133,7 +141,9 @@ export default class Stream {
|
|
|
133
141
|
* @returns {number} The bit mask
|
|
134
142
|
*/
|
|
135
143
|
function bitMask(bitPos) {
|
|
136
|
-
return
|
|
144
|
+
return endianness === "be" ?
|
|
145
|
+
(1 << (8 - bitPos)) - 1 :
|
|
146
|
+
256 - (1 << bitPos);
|
|
137
147
|
}
|
|
138
148
|
}
|
|
139
149
|
|
|
@@ -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;
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
import Operation from "../Operation.mjs";
|
|
8
8
|
import Stream from "../lib/Stream.mjs";
|
|
9
|
-
import {
|
|
9
|
+
import {toHexFast, fromHex} from "../lib/Hex.mjs";
|
|
10
|
+
import {objToTable} from "../lib/Protocol.mjs";
|
|
11
|
+
import Utils from "../Utils.mjs";
|
|
10
12
|
import OperationError from "../errors/OperationError.mjs";
|
|
11
13
|
|
|
12
14
|
/**
|
|
@@ -24,58 +26,61 @@ class ParseUDP extends Operation {
|
|
|
24
26
|
this.module = "Default";
|
|
25
27
|
this.description = "Parses a UDP header and payload (if present).";
|
|
26
28
|
this.infoURL = "https://wikipedia.org/wiki/User_Datagram_Protocol";
|
|
27
|
-
this.inputType = "
|
|
29
|
+
this.inputType = "string";
|
|
28
30
|
this.outputType = "json";
|
|
29
31
|
this.presentType = "html";
|
|
30
|
-
this.args = [
|
|
32
|
+
this.args = [
|
|
33
|
+
{
|
|
34
|
+
name: "Input format",
|
|
35
|
+
type: "option",
|
|
36
|
+
value: ["Hex", "Raw"]
|
|
37
|
+
}
|
|
38
|
+
];
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
/**
|
|
34
|
-
* @param {
|
|
42
|
+
* @param {string} input
|
|
43
|
+
* @param {Object[]} args
|
|
35
44
|
* @returns {Object}
|
|
36
45
|
*/
|
|
37
46
|
run(input, args) {
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
const format = args[0];
|
|
48
|
+
|
|
49
|
+
if (format === "Hex") {
|
|
50
|
+
input = fromHex(input);
|
|
51
|
+
} else if (format === "Raw") {
|
|
52
|
+
input = Utils.strToArrayBuffer(input);
|
|
53
|
+
} else {
|
|
54
|
+
throw new OperationError("Unrecognised input format.");
|
|
40
55
|
}
|
|
41
56
|
|
|
42
57
|
const s = new Stream(new Uint8Array(input));
|
|
58
|
+
if (s.length < 8) {
|
|
59
|
+
throw new OperationError("Need 8 bytes for a UDP Header");
|
|
60
|
+
}
|
|
61
|
+
|
|
43
62
|
// Parse Header
|
|
44
63
|
const UDPPacket = {
|
|
45
64
|
"Source port": s.readInt(2),
|
|
46
65
|
"Destination port": s.readInt(2),
|
|
47
66
|
"Length": s.readInt(2),
|
|
48
|
-
"Checksum":
|
|
67
|
+
"Checksum": "0x" + toHexFast(s.getBytes(2))
|
|
49
68
|
};
|
|
50
69
|
// Parse data if present
|
|
51
70
|
if (s.hasMore()) {
|
|
52
|
-
UDPPacket.Data =
|
|
71
|
+
UDPPacket.Data = "0x" + toHexFast(s.getBytes(UDPPacket.Length - 8));
|
|
53
72
|
}
|
|
54
73
|
|
|
55
74
|
return UDPPacket;
|
|
56
75
|
}
|
|
57
76
|
|
|
58
77
|
/**
|
|
59
|
-
* Displays the UDP Packet in a
|
|
78
|
+
* Displays the UDP Packet in a tabular style
|
|
60
79
|
* @param {Object} data
|
|
61
80
|
* @returns {html}
|
|
62
81
|
*/
|
|
63
82
|
present(data) {
|
|
64
|
-
|
|
65
|
-
html.push("<table class='table table-hover table-sm table-bordered table-nonfluid' style='table-layout: fixed'>");
|
|
66
|
-
html.push("<tr>");
|
|
67
|
-
html.push("<th>Field</th>");
|
|
68
|
-
html.push("<th>Value</th>");
|
|
69
|
-
html.push("</tr>");
|
|
70
|
-
|
|
71
|
-
for (const key in data) {
|
|
72
|
-
html.push("<tr>");
|
|
73
|
-
html.push("<td style=\"word-wrap:break-word\">" + key + "</td>");
|
|
74
|
-
html.push("<td>" + data[key] + "</td>");
|
|
75
|
-
html.push("</tr>");
|
|
76
|
-
}
|
|
77
|
-
html.push("</table>");
|
|
78
|
-
return html.join("");
|
|
83
|
+
return objToTable(data);
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
}
|
|
@@ -229,6 +229,7 @@ import ParseIPv6Address from "./ParseIPv6Address.mjs";
|
|
|
229
229
|
import ParseObjectIDTimestamp from "./ParseObjectIDTimestamp.mjs";
|
|
230
230
|
import ParseQRCode from "./ParseQRCode.mjs";
|
|
231
231
|
import ParseSSHHostKey from "./ParseSSHHostKey.mjs";
|
|
232
|
+
import ParseTCP from "./ParseTCP.mjs";
|
|
232
233
|
import ParseTLV from "./ParseTLV.mjs";
|
|
233
234
|
import ParseUDP from "./ParseUDP.mjs";
|
|
234
235
|
import ParseUNIXFilePermissions from "./ParseUNIXFilePermissions.mjs";
|
|
@@ -601,6 +602,7 @@ export {
|
|
|
601
602
|
ParseObjectIDTimestamp,
|
|
602
603
|
ParseQRCode,
|
|
603
604
|
ParseSSHHostKey,
|
|
605
|
+
ParseTCP,
|
|
604
606
|
ParseTLV,
|
|
605
607
|
ParseUDP,
|
|
606
608
|
ParseUNIXFilePermissions,
|
package/src/node/index.mjs
CHANGED
|
@@ -230,6 +230,7 @@ import {
|
|
|
230
230
|
ParseObjectIDTimestamp as core_ParseObjectIDTimestamp,
|
|
231
231
|
ParseQRCode as core_ParseQRCode,
|
|
232
232
|
ParseSSHHostKey as core_ParseSSHHostKey,
|
|
233
|
+
ParseTCP as core_ParseTCP,
|
|
233
234
|
ParseTLV as core_ParseTLV,
|
|
234
235
|
ParseUDP as core_ParseUDP,
|
|
235
236
|
ParseUNIXFilePermissions as core_ParseUNIXFilePermissions,
|
|
@@ -602,6 +603,7 @@ function generateChef() {
|
|
|
602
603
|
"parseObjectIDTimestamp": _wrap(core_ParseObjectIDTimestamp),
|
|
603
604
|
"parseQRCode": _wrap(core_ParseQRCode),
|
|
604
605
|
"parseSSHHostKey": _wrap(core_ParseSSHHostKey),
|
|
606
|
+
"parseTCP": _wrap(core_ParseTCP),
|
|
605
607
|
"parseTLV": _wrap(core_ParseTLV),
|
|
606
608
|
"parseUDP": _wrap(core_ParseUDP),
|
|
607
609
|
"parseUNIXFilePermissions": _wrap(core_ParseUNIXFilePermissions),
|
|
@@ -991,6 +993,7 @@ const parseIPv6Address = chef.parseIPv6Address;
|
|
|
991
993
|
const parseObjectIDTimestamp = chef.parseObjectIDTimestamp;
|
|
992
994
|
const parseQRCode = chef.parseQRCode;
|
|
993
995
|
const parseSSHHostKey = chef.parseSSHHostKey;
|
|
996
|
+
const parseTCP = chef.parseTCP;
|
|
994
997
|
const parseTLV = chef.parseTLV;
|
|
995
998
|
const parseUDP = chef.parseUDP;
|
|
996
999
|
const parseUNIXFilePermissions = chef.parseUNIXFilePermissions;
|
|
@@ -1365,6 +1368,7 @@ const operations = [
|
|
|
1365
1368
|
parseObjectIDTimestamp,
|
|
1366
1369
|
parseQRCode,
|
|
1367
1370
|
parseSSHHostKey,
|
|
1371
|
+
parseTCP,
|
|
1368
1372
|
parseTLV,
|
|
1369
1373
|
parseUDP,
|
|
1370
1374
|
parseUNIXFilePermissions,
|
|
@@ -1743,6 +1747,7 @@ export {
|
|
|
1743
1747
|
parseObjectIDTimestamp,
|
|
1744
1748
|
parseQRCode,
|
|
1745
1749
|
parseSSHHostKey,
|
|
1750
|
+
parseTCP,
|
|
1746
1751
|
parseTLV,
|
|
1747
1752
|
parseUDP,
|
|
1748
1753
|
parseUNIXFilePermissions,
|
|
@@ -109,11 +109,15 @@ class OperationsWaiter {
|
|
|
109
109
|
const matchedOps = [];
|
|
110
110
|
const matchedDescs = [];
|
|
111
111
|
|
|
112
|
+
// Create version with no whitespace for the fuzzy match
|
|
113
|
+
// Helps avoid missing matches e.g. query "TCP " would not find "Parse TCP"
|
|
114
|
+
const inStrNWS = inStr.replace(/\s/g, "");
|
|
115
|
+
|
|
112
116
|
for (const opName in this.app.operations) {
|
|
113
117
|
const op = this.app.operations[opName];
|
|
114
118
|
|
|
115
119
|
// Match op name using fuzzy match
|
|
116
|
-
const [nameMatch, score, idxs] = fuzzyMatch(
|
|
120
|
+
const [nameMatch, score, idxs] = fuzzyMatch(inStrNWS, opName);
|
|
117
121
|
|
|
118
122
|
// Match description based on exact match
|
|
119
123
|
const descPos = op.description.toLowerCase().indexOf(inStr.toLowerCase());
|
|
@@ -96,6 +96,7 @@ import "./tests/Protobuf.mjs";
|
|
|
96
96
|
import "./tests/ParseSSHHostKey.mjs";
|
|
97
97
|
import "./tests/DefangIP.mjs";
|
|
98
98
|
import "./tests/ParseUDP.mjs";
|
|
99
|
+
import "./tests/ParseTCP.mjs";
|
|
99
100
|
import "./tests/AvroToJSON.mjs";
|
|
100
101
|
import "./tests/Lorenz.mjs";
|
|
101
102
|
import "./tests/LuhnChecksum.mjs";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse TCP tests.
|
|
3
|
+
*
|
|
4
|
+
* @author n1474335
|
|
5
|
+
* @copyright Crown Copyright 2022
|
|
6
|
+
* @license Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
import TestRegister from "../../lib/TestRegister.mjs";
|
|
9
|
+
|
|
10
|
+
TestRegister.addTests([
|
|
11
|
+
{
|
|
12
|
+
name: "Parse TCP: No options",
|
|
13
|
+
input: "c2eb0050a138132e70dc9fb9501804025ea70000",
|
|
14
|
+
expectedMatch: /1026 \(Scaled: 1026\)/,
|
|
15
|
+
recipeConfig: [
|
|
16
|
+
{
|
|
17
|
+
op: "Parse TCP",
|
|
18
|
+
args: ["Hex"],
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "Parse TCP: Options",
|
|
24
|
+
input: "c2eb0050a1380c1f000000008002faf080950000020405b40103030801010402",
|
|
25
|
+
expectedMatch: /1460/,
|
|
26
|
+
recipeConfig: [
|
|
27
|
+
{
|
|
28
|
+
op: "Parse TCP",
|
|
29
|
+
args: ["Hex"],
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "Parse TCP: Timestamps",
|
|
35
|
+
input: "9e90e11574d57b2c00000000a002ffffe5740000020405b40402080aa4e8c8f50000000001030308",
|
|
36
|
+
expectedMatch: /2766719221/,
|
|
37
|
+
recipeConfig: [
|
|
38
|
+
{
|
|
39
|
+
op: "Parse TCP",
|
|
40
|
+
args: ["Hex"],
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
}
|
|
44
|
+
]);
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Parse UDP tests.
|
|
3
3
|
*
|
|
4
4
|
* @author h345983745
|
|
5
|
-
*
|
|
6
5
|
* @copyright Crown Copyright 2019
|
|
7
6
|
* @license Apache-2.0
|
|
8
7
|
*/
|
|
@@ -12,15 +11,11 @@ TestRegister.addTests([
|
|
|
12
11
|
{
|
|
13
12
|
name: "Parse UDP: No Data - JSON",
|
|
14
13
|
input: "04 89 00 35 00 2c 01 01",
|
|
15
|
-
expectedOutput: "{\"Source port\":1161,\"Destination port\":53,\"Length\":44,\"Checksum\":\"
|
|
14
|
+
expectedOutput: "{\"Source port\":1161,\"Destination port\":53,\"Length\":44,\"Checksum\":\"0x0101\"}",
|
|
16
15
|
recipeConfig: [
|
|
17
|
-
{
|
|
18
|
-
op: "From Hex",
|
|
19
|
-
args: ["Auto"],
|
|
20
|
-
},
|
|
21
16
|
{
|
|
22
17
|
op: "Parse UDP",
|
|
23
|
-
args: [],
|
|
18
|
+
args: ["Hex"],
|
|
24
19
|
},
|
|
25
20
|
{
|
|
26
21
|
op: "JSON Minify",
|
|
@@ -30,15 +25,11 @@ TestRegister.addTests([
|
|
|
30
25
|
}, {
|
|
31
26
|
name: "Parse UDP: With Data - JSON",
|
|
32
27
|
input: "04 89 00 35 00 2c 01 01 02 02",
|
|
33
|
-
expectedOutput: "{\"Source port\":1161,\"Destination port\":53,\"Length\":44,\"Checksum\":\"
|
|
28
|
+
expectedOutput: "{\"Source port\":1161,\"Destination port\":53,\"Length\":44,\"Checksum\":\"0x0101\",\"Data\":\"0x0202\"}",
|
|
34
29
|
recipeConfig: [
|
|
35
|
-
{
|
|
36
|
-
op: "From Hex",
|
|
37
|
-
args: ["Auto"],
|
|
38
|
-
},
|
|
39
30
|
{
|
|
40
31
|
op: "Parse UDP",
|
|
41
|
-
args: [],
|
|
32
|
+
args: ["Hex"],
|
|
42
33
|
},
|
|
43
34
|
{
|
|
44
35
|
op: "JSON Minify",
|
|
@@ -51,13 +42,9 @@ TestRegister.addTests([
|
|
|
51
42
|
input: "04 89 00",
|
|
52
43
|
expectedOutput: "Need 8 bytes for a UDP Header",
|
|
53
44
|
recipeConfig: [
|
|
54
|
-
{
|
|
55
|
-
op: "From Hex",
|
|
56
|
-
args: ["Auto"],
|
|
57
|
-
},
|
|
58
45
|
{
|
|
59
46
|
op: "Parse UDP",
|
|
60
|
-
args: [],
|
|
47
|
+
args: ["Hex"],
|
|
61
48
|
},
|
|
62
49
|
{
|
|
63
50
|
op: "JSON Minify",
|