From cfb9c371e01561d650ce1645ebf090f4aa8f89fb Mon Sep 17 00:00:00 2001 From: Alexey Oplachko Date: Mon, 25 Mar 2024 14:33:27 +0200 Subject: [PATCH] fix: TCP packets in PCAP 1 --- src/components/SimplePanel.tsx | 55 ++++++++++++++++++------- src/libs/packets.js | 73 ++++++++++++++++++++++++++++++---- 2 files changed, 106 insertions(+), 22 deletions(-) diff --git a/src/components/SimplePanel.tsx b/src/components/SimplePanel.tsx index 43caf18..7f8ffda 100644 --- a/src/components/SimplePanel.tsx +++ b/src/components/SimplePanel.tsx @@ -13,6 +13,8 @@ import { Buffer } from 'buffer' const ip = packets.ipPacket const udp = packets.udpPacket const tcp = packets.tcpPacket +const ethernet = packets.ethernetPacket + import { Button, @@ -215,7 +217,9 @@ function formattingDataAndSortIt(data: any, sortType = 'none') { } - +interface Labels { + [key: string]: string +} export const SimplePanel: React.FC = ({ options, data, width, height }: any) => { @@ -274,17 +278,25 @@ export const SimplePanel: React.FC = ({ options, data, width, height }: a const [serie]: any = (data as any)?.series || []; const fields = serie?.fields || []; const lineField = fields.find((i: any) => i.name === 'Line') ?? []; - const packets2 = lineField?.values.map((field: string, index: number) => { - - const labels = fields[0]?.values[index] + const values = fields[0]?.values.map((item: any, index: number) => { + item.line = lineField?.values[index]; + return item + }).filter((packet: any) => packet.type === 'sip') + const sequenceMap = new Map(); + const ipv4_regex = /(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}/; + const packets2 = values.sort((a: any, b: any) => { + return a.timestamp - b.timestamp + }).map((labels: Labels, index: number) => { + let line = labels.line let proto = '' - if (field.includes('UDP')) { + line = line?.replace('UDP', 'TCP') + if (line.includes('UDP')) { proto += "UDP" - } else if (field.includes('TCP')) { + } else if (line.includes('TCP')) { proto += "TCP" } const fieldObj = { - data: field, + data: line, srcIp: labels.src_ip, dstIp: labels.dst_ip, srcPort: labels.src_port, @@ -296,19 +308,25 @@ export const SimplePanel: React.FC = ({ options, data, width, height }: a flowLabel: 0, nextHeader: proto === 'UDP' ? 17 : 6 } - const ipv4_regex = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/gm; - + const hash = `${fieldObj.srcIp}:${fieldObj.srcPort}->${fieldObj.dstIp}:${fieldObj.dstPort}` + const sequence = sequenceMap.get(hash) ?? 1 const packet_data = proto === 'UDP' ? udp.encode({ sourcePort: fieldObj.srcPort, destinationPort: fieldObj.dstPort, - data: Buffer.from(fieldObj.data) + data: Buffer.from(line) }) : tcp.encode({ sourcePort: fieldObj.srcPort, destinationPort: fieldObj.dstPort, - data: Buffer.from(fieldObj.data) + data: Buffer.from(line), + sequenceNumber: sequence, + acknowledgmentNumber: 0, + ack: true, + psh: true, + syn: false, }) + let ip_packet = ip.encode({ - version: ipv4_regex.test(fieldObj.srcIp) ? 4 : 6, + version: ipv4_regex.test(fieldObj.dstIp) ? 4 : 6, protocol: fieldObj.proto, sourceIp: fieldObj.srcIp, destinationIp: fieldObj.dstIp, @@ -318,13 +336,20 @@ export const SimplePanel: React.FC = ({ options, data, width, height }: a trafficClass: fieldObj.trafficClass, flowLabel: fieldObj.flowLabel }) + let ethernetPacket = ethernet.encode({ + data: ip_packet, + type: ipv4_regex.test(fieldObj.dstIp) ? '0800' : '86dd' + }) + if (proto === 'TCP') { + sequenceMap.set(hash, (sequenceMap.get(hash) ?? 1) + Buffer.from(line).length) + } return { timestamp: fieldObj.ts, - buffer: ip_packet, + buffer: ethernetPacket, type: fields[0]?.values[index]?.type } - }).filter((packet: any) => packet.type === 'sip') - const generator = configure({ Buffer: Buffer }) + }) + const generator = configure({ Buffer: Buffer, snapshotLength: 102400, linkLayerType: 1 }) const pcapFile = generator(packets2) const blob = new Blob([pcapFile], { type: 'application/vnd.tcpdump.pcap' }); // // Create element with tag diff --git a/src/libs/packets.js b/src/libs/packets.js index dbfa995..6da70b1 100644 --- a/src/libs/packets.js +++ b/src/libs/packets.js @@ -2028,9 +2028,10 @@ module.exports = { 'ipPacket': require('./ip-packet'), 'udpPacket': require('./udp-packet'), - 'tcpPacket': require('./tcp-packet') + 'tcpPacket': require('./tcp-packet'), + 'ethernetPacket': require('./ethernet-packet') } - }, { "./ip-packet": 5, "./tcp-packet": 6, "./udp-packet": 7 }], 5: [function (require, module, exports) { + }, { "./ip-packet": 5, "./tcp-packet": 6, "./udp-packet": 7, "./ethernet-packet": 8 }], 5: [function (require, module, exports) { (function (Buffer) { (function () { module.exports = configure({}) @@ -2061,7 +2062,7 @@ buf.writeUInt32BE(packet.version << 28 | (packet.trafficClass << 20) | packet.flowLabel, offset); buf.writeUInt16BE(packet.data.length, offset + 4); buf[offset + 6] = packet.nextHeader; - buf[offset + 7] = packet.hopLimit; + buf[offset + 7] = packet.hopLimit || 64; const sourceIpBuffer = Buffer.from(packet.sourceIp); const destinationIpBuffer = Buffer.from(packet.destinationIp); @@ -2158,16 +2159,56 @@ (function () { exports.encode = encode exports.decode = decode - - function encode({ data, sourcePort, destinationPort, sequenceNumber = 0, acknowledgmentNumber = 0 }) { + function tcpChecksum(packet, buf) { + // pseudo header: srcip (16), dstip (16), 0 (8), proto (8), udp len (16) + let len = buf.length + let srcip = packet.sourceIp + let dstip = packet.destinationIp + if (!srcip || !dstip) { return 0xffff } + let protocol = packet.protocol === undefined ? 0x11 : packet.protocol + let sum = 0xffff + // pseudo header: srcip (16), dstip (16), 0 (8), proto (8), udp len (16) + if (srcip && dstip) { + if (typeof srcip === 'string') { srcip = Buffer.from(srcip.split('.')) } + if (typeof dstip === 'string') { dstip = Buffer.from(dstip.split('.')) } + sum = 0 + let pad = len % 2 + for (let i = 0; i < len + pad; i += 2) { + if (i === 6) { continue } // ignore the currently written checksum + sum += ((buf[i] << 8) & 0xff00) + ((buf[i + 1]) & 0xff) + } + for (let i = 0; i < 4; i += 2) { + sum += ((srcip[i] << 8) & 0xff00) + (srcip[i + 1] & 0xff) + } + for (let i = 0; i < 4; i += 2) { + sum += ((dstip[i] << 8) & 0xff00) + (dstip[i + 1] & 0xff) + } + sum += protocol + len + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16) + } + sum = 0xffff ^ sum + } + return sum + } + function encode({ data, sourcePort, destinationPort, sequenceNumber = 0, acknowledgmentNumber = 0, ack = false, psh = false, syn = false }) { const dataLength = data ? data.length : 0 - const packet = Buffer.alloc(dataLength) + const packet = Buffer.alloc(dataLength + 20) packet.writeUInt16BE(sourcePort, 0) packet.writeUInt16BE(destinationPort, 2) packet.writeUInt32BE(sequenceNumber, 4) packet.writeUInt32BE(acknowledgmentNumber, 8) - packet.writeUInt16BE(0x5000, 12) + packet.writeUInt16BE(((20 / 4) << 12), 12); + const setAck = (ack) ? (1 << 4) : (0 << 4) + const setPsh = (psh) ? (1 << 3) : (0 << 3) + const setSyn = (syn) ? (1 << 1) : (0 << 1) + const flags = setSyn | setPsh | setAck + packet.writeUInt8(flags, 13); + packet.writeUInt16BE(8235, 14); + packet.writeUInt16BE(0, 16); if (data) { data.copy(packet, 20) } + const checksum = tcpChecksum(data, packet); + packet.writeUInt16BE(checksum, 16) return packet } @@ -2264,6 +2305,24 @@ }).call(this) }).call(this, require("buffer").Buffer) + }, { "buffer": 2 }], 8: [function (require, module, exports) { + (function (Buffer) { + (function () { + exports.encode = encodeEthernetFrame + function encodeEthernetFrame({ destinationMac = '11:22:33:44:55:66', sourceMac = 'aa:bb:cc:dd:ee:ff', type, data }) { + const ethernetFrameLength = 14; // Length of Ethernet frame header + const totalLength = ethernetFrameLength + data.length; + const frame = Buffer.alloc(totalLength); + + destinationMac.split(':').forEach((byte, index) => frame.writeUInt8(parseInt(byte, 16), index)); + sourceMac.split(':').forEach((byte, index) => frame.writeUInt8(parseInt(byte, 16), index + 6)); + frame.writeUInt16BE(parseInt(type, 16), 12); // EtherType + data.copy(frame, ethernetFrameLength); // Copy payload to frame + + return frame; + } + }).call(this) + }).call(this, require("buffer").Buffer) }, { "buffer": 2 }] }, {}, [4])(4) });