netkitty
Version:
Network tools kit
900 lines (899 loc) • 49.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TCP = void 0;
const BaseHeader_1 = require("../abstracts/BaseHeader");
const BufferToNumber_1 = require("../../helper/BufferToNumber");
const NumberToBuffer_1 = require("../../helper/NumberToBuffer");
const IPToBuffer_1 = require("../../helper/IPToBuffer");
const StringContentEncodingEnum_1 = require("../lib/StringContentEncodingEnum");
const NumberToHex_1 = require("../../helper/NumberToHex");
const HexToNumber_1 = require("../../helper/HexToNumber");
var TCPOption;
(function (TCPOption) {
TCPOption["End_of_Option_List"] = "EOL";
TCPOption["No_Operation"] = "NOP";
TCPOption["Maximum_Segment_Size"] = "MSS";
TCPOption["Window_Scale"] = "Window-Scale";
TCPOption["Selective_Acknowledgment_Permitted"] = "SACK-Permitted";
TCPOption["Selective_Acknowledgment"] = "SACK";
TCPOption["Timestamp"] = "TS";
TCPOption["User_Timeout"] = "UTO";
TCPOption["TCP_Authentication_Option"] = "TCP-AO";
})(TCPOption || (TCPOption = {}));
class TCP extends BaseHeader_1.BaseHeader {
constructor() {
super(...arguments);
this.SCHEMA = {
type: 'object',
properties: {
srcport: {
type: 'integer',
label: 'Source Port',
minimum: 0,
maximum: 65535,
decode: () => {
this.instance.srcport.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(0, 2)));
},
encode: () => {
let srcport = this.instance.srcport.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (srcport > 65535) {
this.recordError(this.instance.srcport.getPath(), 'Maximum value is 65535');
srcport = 65535;
}
if (srcport < 0) {
this.recordError(this.instance.srcport.getPath(), 'Minimum value is 0');
srcport = 0;
}
this.instance.srcport.setValue(srcport);
this.writeBytes(0, (0, NumberToBuffer_1.UInt16ToBuffer)(srcport));
}
},
dstport: {
type: 'integer',
label: 'Destination Port',
minimum: 0,
maximum: 65535,
decode: () => {
this.instance.dstport.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(2, 2)));
},
encode: () => {
let dstport = this.instance.dstport.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (dstport > 65535) {
this.recordError(this.instance.dstport.getPath(), 'Maximum value is 65535');
dstport = 65535;
}
if (dstport < 0) {
this.recordError(this.instance.dstport.getPath(), 'Minimum value is 0');
dstport = 0;
}
this.instance.dstport.setValue(dstport);
this.writeBytes(2, (0, NumberToBuffer_1.UInt16ToBuffer)(dstport));
}
},
seq: {
type: 'integer',
label: 'Sequence Number',
minimum: 0,
maximum: 4294967295,
decode: () => {
this.instance.seq.setValue((0, BufferToNumber_1.BufferToUInt32)(this.readBytes(4, 4)));
},
encode: () => {
let seqNum = this.instance.seq.getValue(0);
if (seqNum > 4294967295) {
this.recordError(this.instance.seq.getPath(), 'Maximum value is 4294967295');
seqNum = 4294967295;
}
if (seqNum < 0) {
this.recordError(this.instance.seq.getPath(), 'Minimum value is 0');
seqNum = 0;
}
this.instance.seq.setValue(seqNum);
this.writeBytes(4, (0, NumberToBuffer_1.UInt32ToBuffer)(seqNum));
}
},
ack: {
type: 'integer',
label: 'Acknowledgment Number',
minimum: 0,
maximum: 4294967295,
decode: () => {
this.instance.ack.setValue((0, BufferToNumber_1.BufferToUInt32)(this.readBytes(8, 4)));
},
encode: () => {
let ackNum = this.instance.ack.getValue(0);
if (ackNum > 4294967295) {
this.recordError(this.instance.ack.getPath(), 'Maximum value is 4294967295');
ackNum = 4294967295;
}
if (ackNum < 0) {
this.recordError(this.instance.ack.getPath(), 'Minimum value is 0');
ackNum = 0;
}
this.instance.ack.setValue(ackNum);
this.writeBytes(8, (0, NumberToBuffer_1.UInt32ToBuffer)(ackNum));
}
},
hdrLen: {
type: 'integer',
label: 'Header Length',
minimum: 0,
maximum: 60,
decode: () => {
this.instance.hdrLen.setValue(this.readBits(12, 1, 0, 4) * 4);
},
encode: () => {
let hdrLen = this.instance.hdrLen.getValue(0);
if (hdrLen) {
this.instance.hdrLen.setValue(hdrLen);
this.writeBits(12, 1, 0, 4, hdrLen ? Math.floor(hdrLen / 4) : 0);
}
else {
this.addPostSelfEncodeHandler(() => {
this.instance.hdrLen.setValue(Math.floor(this.length / 4) * 4);
this.writeBits(12, 1, 0, 4, Math.floor(this.length / 4));
}, 1);
}
}
},
flags: {
type: 'object',
label: 'Flags',
properties: {
res: {
type: 'integer',
label: 'Reserved',
minimum: 0,
maximum: 7,
decode: () => {
this.instance.flags.res.setValue(this.readBits(12, 1, 4, 3));
},
encode: () => {
let reserved = this.instance.flags.res.getValue(0);
if (reserved > 7) {
this.recordError(this.instance.flags.res.getPath(), 'Maximum value is 7');
reserved = 7;
}
if (reserved < 0) {
this.recordError(this.instance.flags.res.getPath(), 'Minimum value is 0');
reserved = 0;
}
this.instance.flags.res.setValue(reserved);
this.writeBits(12, 1, 4, 3, reserved);
}
},
ae: {
type: 'boolean',
label: 'Accurate ECN',
decode: () => {
this.instance.flags.ae.setValue(!!this.readBits(12, 1, 7, 1));
},
encode: () => {
const accurateECN = !!this.instance.flags.ae.getValue();
this.instance.flags.ae.setValue(accurateECN);
this.writeBits(12, 1, 7, 1, accurateECN ? 1 : 0);
}
},
cwr: {
type: 'boolean',
label: 'Congestion Window Reduced',
decode: () => {
this.instance.flags.cwr.setValue(!!this.readBits(13, 1, 0, 1));
},
encode: () => {
const congestionWindowReduced = !!this.instance.flags.cwr.getValue();
this.instance.flags.cwr.setValue(congestionWindowReduced);
this.writeBits(13, 1, 0, 1, congestionWindowReduced ? 1 : 0);
}
},
ece: {
type: 'boolean',
label: 'ECN-Echo',
decode: () => {
this.instance.flags.ece.setValue(!!this.readBits(13, 1, 1, 1));
},
encode: () => {
const ECNEcho = !!this.instance.flags.ece.getValue();
this.instance.flags.ece.setValue(ECNEcho);
this.writeBits(13, 1, 1, 1, ECNEcho ? 1 : 0);
}
},
urg: {
type: 'boolean',
label: 'Urgent',
decode: () => {
this.instance.flags.urg.setValue(!!this.readBits(13, 1, 2, 1));
},
encode: () => {
const urgent = !!this.instance.flags.urg.getValue();
this.instance.flags.urg.setValue(urgent);
this.writeBits(13, 1, 2, 1, urgent ? 1 : 0);
}
},
ack: {
type: 'boolean',
label: 'Acknowledgment',
decode: () => {
this.instance.flags.ack.setValue(!!this.readBits(13, 1, 3, 1));
},
encode: () => {
const acknowledgment = !!this.instance.flags.ack.getValue();
this.instance.flags.ack.setValue(acknowledgment);
this.writeBits(13, 1, 3, 1, acknowledgment ? 1 : 0);
}
},
push: {
type: 'boolean',
label: 'Push',
decode: () => {
this.instance.flags.push.setValue(!!this.readBits(13, 1, 4, 1));
},
encode: () => {
const push = !!this.instance.flags.push.getValue();
this.instance.flags.push.setValue(push);
this.writeBits(13, 1, 4, 1, push ? 1 : 0);
}
},
rst: {
type: 'boolean',
label: 'Reset',
decode: () => {
this.instance.flags.rst.setValue(!!this.readBits(13, 1, 5, 1));
},
encode: () => {
const reset = !!this.instance.flags.rst.getValue();
this.instance.flags.rst.setValue(reset);
this.writeBits(13, 1, 5, 1, reset ? 1 : 0);
}
},
syn: {
type: 'boolean',
label: 'Syn',
decode: () => {
this.instance.flags.syn.setValue(!!this.readBits(13, 1, 6, 1));
},
encode: () => {
const syn = !!this.instance.flags.syn.getValue();
this.instance.flags.syn.setValue(syn);
this.writeBits(13, 1, 6, 1, syn ? 1 : 0);
}
},
fin: {
type: 'boolean',
label: 'Fin',
decode: () => {
this.instance.flags.fin.setValue(!!this.readBits(13, 1, 7, 1));
},
encode: () => {
const fin = !!this.instance.flags.fin.getValue();
this.instance.flags.fin.setValue(fin);
this.writeBits(13, 1, 7, 1, fin ? 1 : 0);
}
}
}
},
window: {
type: 'integer',
label: 'Window Size',
minimum: 0,
maximum: 65535,
decode: () => {
this.instance.window.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(14, 2)));
},
encode: () => {
let windowSize = this.instance.window.getValue(0);
if (windowSize > 65535) {
this.recordError(this.instance.window.getPath(), 'Maximum value is 65535');
windowSize = 65535;
}
if (windowSize < 0) {
this.recordError(this.instance.window.getPath(), 'Minimum value is 0');
windowSize = 0;
}
this.instance.window.setValue(windowSize);
this.writeBytes(14, (0, NumberToBuffer_1.UInt16ToBuffer)(windowSize));
}
},
checksum: {
type: 'integer',
label: 'Checksum',
minimum: 0,
maximum: 65535,
decode: () => {
this.instance.checksum.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(16, 2)));
},
encode: () => {
let checksum = this.instance.checksum.getValue(0);
if (checksum) {
this.instance.checksum.setValue(checksum);
this.writeBytes(16, (0, NumberToBuffer_1.UInt16ToBuffer)(checksum));
}
else {
this.instance.checksum.setValue(checksum);
this.writeBytes(16, (0, NumberToBuffer_1.UInt16ToBuffer)(checksum));
this.addPostPacketEncodeHandler(() => {
//Calculate checksum after packet encoded
let startPos = 0;
let endPos = 0;
this.codecModules.forEach((codecModule) => {
if (codecModule === this)
startPos = codecModule.startPos;
endPos = codecModule.endPos > endPos ? codecModule.endPos : endPos;
});
const calcChecksum = this.calculateTCPChecksum(this.packet.subarray(startPos, endPos));
this.instance.checksum.setValue(calcChecksum);
this.writeBytes(16, (0, NumberToBuffer_1.UInt16ToBuffer)(calcChecksum));
}, 100);
}
}
},
urgPtr: {
type: 'integer',
label: 'Urgent Pointer',
minimum: 0,
maximum: 65535,
decode: () => {
this.instance.urgPtr.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(18, 2)));
},
encode: () => {
let urgPtr = this.instance.urgPtr.getValue(0);
if (urgPtr > 65535) {
this.recordError(this.instance.urgPtr.getPath(), 'Maximum value is 65535');
urgPtr = 65535;
}
if (urgPtr < 0) {
this.recordError(this.instance.urgPtr.getPath(), 'Minimum value is 0');
urgPtr = 0;
}
this.instance.urgPtr.setValue(urgPtr);
this.writeBytes(18, (0, NumberToBuffer_1.UInt16ToBuffer)(urgPtr));
}
},
options: {
type: 'array',
label: 'Options',
items: {
anyOf: [
//Kind = 0 (End of Option List, EOL)
{
type: 'object',
label: 'End of Option List',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.End_of_Option_List]
}
}
},
//Kind = 1 (No-Operation, NOP)
{
type: 'object',
label: 'No-Operation',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.No_Operation]
}
}
},
//Kind = 2 (Maximum Segment Size, MSS)
{
type: 'object',
label: 'Maximum Segment Size',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.Maximum_Segment_Size]
},
mss: {
type: 'integer',
label: 'MSS',
maximum: 65535,
minimum: 0
}
}
},
//Kind = 3 (Window Scale)
{
type: 'object',
label: 'Window Scale',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.Window_Scale]
},
shift: {
type: 'integer',
label: 'Shift count',
minimum: 0,
maximum: 14
}
}
},
//Kind = 4 (Selective Acknowledgment Permitted, SACK-Permitted)
{
type: 'object',
label: 'Selective Acknowledgment Permitted',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.Selective_Acknowledgment_Permitted]
}
}
},
//Kind = 5 (Selective Acknowledgment, SACK)
{
type: 'object',
label: 'Selective Acknowledgment',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.Selective_Acknowledgment]
},
blocks: {
type: 'array',
label: 'SACK Blocks',
items: {
type: 'string',
maxLength: 16,
minLength: 16,
contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.HEX
}
}
}
},
//Kind = 8 (Timestamp, TS)
{
type: 'object',
label: 'Timestamp',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.Timestamp]
},
tsval: {
type: 'integer',
label: 'TSval',
minimum: 0,
maximum: 4294967295
},
tsecr: {
type: 'integer',
label: 'TSecr',
minimum: 0,
maximum: 4294967295
}
}
},
//Kind = 28 (User Timeout, UTO)
{
type: 'object',
label: 'User Timeout',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.User_Timeout]
},
timeout: {
type: 'integer',
label: 'Timeout',
minimum: 0,
maximum: 65535
},
granularity: {
type: 'integer',
label: 'Granularity',
enum: [0, 1]
}
}
},
//Kind = 29 (TCP Authentication Option, TCP-AO)
{
type: 'object',
label: 'TCP Authentication Option',
properties: {
option: {
type: 'string',
label: 'Option',
enum: [TCPOption.TCP_Authentication_Option]
},
data: {
type: 'string',
label: 'Data',
contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.HEX
}
}
},
//Default
{
type: 'object',
label: 'Default',
properties: {
kind: {
type: 'integer',
label: 'Kind'
},
data: {
type: 'string',
contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.HEX,
label: 'Data'
}
}
}
]
},
decode: () => {
const hdrLen = this.instance.hdrLen.getValue();
const optionsLength = hdrLen - this.length;
if (!optionsLength)
return;
let optionOffset = this.length;
const options = [];
let index = 0;
while (optionOffset < hdrLen) {
const kind = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
optionOffset += 1;
switch (kind) {
//Kind = 0 (End of Option List, EOL)
case 0:
{
options.push({
option: TCPOption.End_of_Option_List
});
}
break;
//Kind = 1 (No-Operation, NOP)
case 1:
{
options.push({
option: TCPOption.No_Operation
});
}
break;
//Kind = 2 (Maximum Segment Size, MSS)
case 2:
{
let length = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
if (length !== 4)
this.recordError(this.instance.options.getPath(index), 'MSS option TLV length should be 4');
optionOffset += 1;
let value = (0, BufferToNumber_1.BufferToUInt16)(this.readBytes(optionOffset, 2));
optionOffset += 2;
options.push({
option: TCPOption.Maximum_Segment_Size,
mss: value
});
}
break;
//Kind = 3 (Window Scale)
case 3:
{
let length = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
if (length !== 3)
this.recordError(this.instance.options.getPath(index), 'Window Scale option TLV length should be 3');
optionOffset += 1;
let value = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
optionOffset += 1;
if (value < 0 || value > 14)
this.recordError(this.instance.options.getPath(index), 'Window Scale option TLV value should between 0 and 14');
options.push({
option: TCPOption.Window_Scale,
shift: value
});
}
break;
//Kind = 4 (Selective Acknowledgment Permitted, SACK-Permitted)
case 4:
{
let length = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
optionOffset += 1;
if (length !== 2)
this.recordError(this.instance.options.getPath(index), 'SACK-Permitted option TLV length should be 2');
options.push({
option: TCPOption.Selective_Acknowledgment_Permitted
});
}
break;
//Kind = 5 (Selective Acknowledgment, SACK)
case 5:
{
let length = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
optionOffset += 1;
let sackBlockTotalLength = length - 2;
if (sackBlockTotalLength < 0) {
this.recordError(this.instance.options.getPath(index), 'SACK option block count should not less than 0');
sackBlockTotalLength = 0;
}
let sackBlockCount = sackBlockTotalLength ? Math.floor(sackBlockTotalLength / 8) : 0;
const sackBlocks = [];
while (sackBlockCount > 0) {
sackBlocks.push((0, NumberToHex_1.UInt64ToHex)(BigInt(`0x${(0, BufferToNumber_1.BufferToUInt64)(this.readBytes(optionOffset, 8)).toString(16)}`)));
optionOffset += 8;
sackBlockCount -= 1;
}
options.push({
option: TCPOption.Selective_Acknowledgment,
blocks: sackBlocks
});
}
break;
//Kind = 8 (Timestamp, TS)
case 8:
{
let length = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
optionOffset += 1;
if (length !== 10)
this.recordError(this.instance.options.getPath(index), 'Timestamp option TLV length should be 10');
let tsval = (0, BufferToNumber_1.BufferToUInt32)(this.readBytes(optionOffset, 4));
optionOffset += 4;
let tsecr = (0, BufferToNumber_1.BufferToUInt32)(this.readBytes(optionOffset, 4));
optionOffset += 4;
options.push({
option: TCPOption.Timestamp,
tsval: tsval,
tsecr: tsecr
});
}
break;
//Kind = 28 (User Timeout, UTO)
case 28:
{
let length = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
optionOffset += 1;
if (length !== 5)
this.recordError(this.instance.options.getPath(index), 'UTO option TLV length should be 5');
let timeout = (0, BufferToNumber_1.BufferToUInt16)(this.readBytes(optionOffset, 2));
optionOffset += 2;
let granularity = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
optionOffset += 1;
options.push({
option: TCPOption.User_Timeout,
timeout: timeout,
granularity: granularity
});
}
break;
//Kind = 29 (TCP Authentication Option, TCP-AO)
case 29:
{
let length = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
optionOffset += 1;
let dataLength = length - 2;
if (dataLength < 0) {
this.recordError(this.instance.options.getPath(index), 'TCP Authentication Option TLV length should not less than 2');
dataLength = 0;
}
let data;
if (dataLength) {
data = this.readBytes(optionOffset, dataLength);
optionOffset += dataLength;
}
else {
data = Buffer.from([]);
}
options.push({
option: TCPOption.TCP_Authentication_Option,
data: data.toString('hex')
});
}
break;
default: {
let length = (0, BufferToNumber_1.BufferToUInt8)(this.readBytes(optionOffset, 1));
let dataLength = length - 2;
if (dataLength < 0) {
this.recordError(this.instance.options.getPath(index), 'Option TLV length should not less than 2');
dataLength = 0;
}
let data;
if (dataLength) {
data = this.readBytes(optionOffset, dataLength);
optionOffset += dataLength;
}
else {
data = Buffer.from([]);
}
options.push({
kind: kind,
data: data.toString('hex')
});
}
}
index += 1;
}
this.instance.options.setValue(options);
},
encode: () => {
const options = this.instance.options.getValue();
if (!options)
return;
let optionOffset = this.length;
options.forEach((optionItem) => {
const namedOptionItem = optionItem;
switch (namedOptionItem.option) {
case TCPOption.End_of_Option_List: {
const optionEOL = optionItem;
this.writeBytes(optionOffset, (0, NumberToBuffer_1.UInt8ToBuffer)(0));
optionOffset += 1;
return;
}
case TCPOption.No_Operation: {
const optionNOP = optionItem;
this.writeBytes(optionOffset, (0, NumberToBuffer_1.UInt8ToBuffer)(1));
optionOffset += 1;
return;
}
case TCPOption.Maximum_Segment_Size: {
const optionMSS = optionItem;
const mssBuffer = Buffer.concat([
(0, NumberToBuffer_1.UInt8ToBuffer)(2),
(0, NumberToBuffer_1.UInt8ToBuffer)(4),
(0, NumberToBuffer_1.UInt16ToBuffer)(optionMSS.mss)
]);
this.writeBytes(optionOffset, mssBuffer);
optionOffset += mssBuffer.length;
return;
}
case TCPOption.Window_Scale: {
const optionWS = optionItem;
const wsBuffer = Buffer.concat([
(0, NumberToBuffer_1.UInt8ToBuffer)(3),
(0, NumberToBuffer_1.UInt8ToBuffer)(3),
(0, NumberToBuffer_1.UInt8ToBuffer)(optionWS.shift)
]);
this.writeBytes(optionOffset, wsBuffer);
optionOffset += wsBuffer.length;
return;
}
case TCPOption.Selective_Acknowledgment_Permitted: {
const optionSackPermitted = optionItem;
const sackPermittedBuffer = Buffer.concat([
(0, NumberToBuffer_1.UInt8ToBuffer)(4),
(0, NumberToBuffer_1.UInt8ToBuffer)(2)
]);
this.writeBytes(optionOffset, sackPermittedBuffer);
optionOffset += sackPermittedBuffer.length;
return;
}
case TCPOption.Selective_Acknowledgment: {
const optionSack = optionItem;
const kindBuffer = (0, NumberToBuffer_1.UInt8ToBuffer)(5);
let length = 2;
let blocksBuffer = Buffer.from([]);
optionSack.blocks.forEach((block) => {
blocksBuffer = Buffer.concat([blocksBuffer, (0, NumberToBuffer_1.UInt64ToBuffer)((0, HexToNumber_1.HexToUInt64)(block))]);
});
const sackBuffer = Buffer.concat([kindBuffer, (0, NumberToBuffer_1.UInt8ToBuffer)(length + blocksBuffer.length), blocksBuffer]);
this.writeBytes(optionOffset, sackBuffer);
optionOffset += sackBuffer.length;
return;
}
case TCPOption.Timestamp: {
const optionTS = optionItem;
const tsBuffer = Buffer.concat([
(0, NumberToBuffer_1.UInt8ToBuffer)(8),
(0, NumberToBuffer_1.UInt8ToBuffer)(10),
(0, NumberToBuffer_1.UInt32ToBuffer)(optionTS.tsval ? optionTS.tsval : 0),
(0, NumberToBuffer_1.UInt32ToBuffer)(optionTS.tsecr ? optionTS.tsecr : 0)
]);
this.writeBytes(optionOffset, tsBuffer);
optionOffset += tsBuffer.length;
return;
}
case TCPOption.User_Timeout: {
const optionUTO = optionItem;
const utoBuffer = Buffer.concat([
(0, NumberToBuffer_1.UInt8ToBuffer)(28),
(0, NumberToBuffer_1.UInt8ToBuffer)(5),
(0, NumberToBuffer_1.UInt16ToBuffer)(optionUTO.timeout ? optionUTO.timeout : 0),
(0, NumberToBuffer_1.UInt8ToBuffer)(optionUTO.granularity ? optionUTO.granularity : 0)
]);
this.writeBytes(optionOffset, utoBuffer);
optionOffset += utoBuffer.length;
return;
}
case TCPOption.TCP_Authentication_Option: {
const optionTcpAo = optionItem;
const kindBuffer = (0, NumberToBuffer_1.UInt8ToBuffer)(29);
const dataBuffer = Buffer.from(optionTcpAo.data, 'hex');
const lengthBuffer = (0, NumberToBuffer_1.UInt8ToBuffer)(dataBuffer.length + 2);
const tcpAoBuffer = Buffer.concat([kindBuffer, lengthBuffer, dataBuffer]);
this.writeBytes(optionOffset, tcpAoBuffer);
optionOffset += tcpAoBuffer.length;
return;
}
default: {
const defaultOptionItem = optionItem;
const kind = defaultOptionItem.kind;
const hexBuffer = Buffer.from(defaultOptionItem.data.toString(), 'hex');
const length = hexBuffer.length + 2;
const defaultOptionBuffer = Buffer.concat([(0, NumberToBuffer_1.UInt8ToBuffer)(kind), (0, NumberToBuffer_1.UInt8ToBuffer)(length), hexBuffer]);
this.writeBytes(optionOffset, defaultOptionBuffer);
optionOffset += defaultOptionBuffer.length;
}
}
});
if (this.length > 60)
return this.recordError(this.instance.options.getPath(), 'Options too large');
const headerBitLength = this.length * 8;
if (headerBitLength % 4) {
//Add Padding
this.writeBytes(this.length, Buffer.from([0x00]));
}
}
}
}
};
this.id = 'tcp';
this.name = 'Transmission Control Protocol';
this.nickname = 'TCP';
}
/**
* Calculate TCP Checksum
* @param tcpHeaderBuffer
* @protected
*/
calculateTCPChecksum(tcpHeaderBuffer) {
const tcpHeaderLength = tcpHeaderBuffer.length;
const ipVersion = this.prevCodecModule.instance.version.getValue();
let pseudoHeaderBuffer = Buffer.from([]);
const sourceIp = this.prevCodecModule.instance.sip.getValue();
const destinationIp = this.prevCodecModule.instance.dip.getValue();
if (ipVersion === 4) {
//4 Bytes
const sourceIPv4Buffer = Buffer.from(sourceIp.split('.').map((value) => parseInt(value)));
const destinationIPv4Buffer = Buffer.from(destinationIp.split('.').map((value) => parseInt(value)));
//IPv4 Pseudo header
pseudoHeaderBuffer = Buffer.concat([
sourceIPv4Buffer,
destinationIPv4Buffer,
(0, NumberToBuffer_1.UInt8ToBuffer)(0), //Reserved field
(0, NumberToBuffer_1.UInt8ToBuffer)(6), //Protocol type (TCP = 6)
Buffer.from([(tcpHeaderLength >> 8) & 0xFF]),
Buffer.from([tcpHeaderLength & 0xFF])
]);
}
else if (ipVersion === 6) {
//16 Bytes
const sourceIPv6Buffer = (0, IPToBuffer_1.IPv6ToBuffer)(sourceIp);
const destinationIPv6Buffer = (0, IPToBuffer_1.IPv6ToBuffer)(destinationIp);
//IPv6 Pseudo header
pseudoHeaderBuffer = Buffer.concat([
sourceIPv6Buffer,
destinationIPv6Buffer,
(0, NumberToBuffer_1.UInt8ToBuffer)(0), //Reserved field
(0, NumberToBuffer_1.UInt8ToBuffer)(0), //Reserved field
(0, NumberToBuffer_1.UInt8ToBuffer)(0), //Reserved field
(0, NumberToBuffer_1.UInt8ToBuffer)(6), //Protocol type (TCP = 6)
Buffer.from([(tcpHeaderLength >> 8) & 0xFF]),
Buffer.from([tcpHeaderLength & 0xFF])
]);
}
else {
return 0;
}
const dataBuffer = Buffer.concat([pseudoHeaderBuffer, tcpHeaderBuffer]);
const data = Uint8Array.from(dataBuffer);
let sum = 0;
for (let i = 0; i < data.length; i += 2)
sum += (data[i] << 8) + (data[i + 1] || 0);
while (sum >>> 16)
sum = (sum & 0xFFFF) + (sum >>> 16);
return (~sum) & 0xFFFF;
}
match() {
if (!this.prevCodecModule)
return false;
if (this.prevCodecModule.instance.protocol.getValue() === 0x06)
return true;
return false;
}
}
exports.TCP = TCP;