|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function parseTCPHeader(packet, ipHeaderLength) { |
|
|
if (packet.length < ipHeaderLength + 20) { |
|
|
throw new Error('TCP数据包太短,无法解析TCP头部'); |
|
|
} |
|
|
|
|
|
const tcpStart = ipHeaderLength; |
|
|
const sourcePort = (packet[tcpStart] << 8) + packet[tcpStart + 1]; |
|
|
const destPort = (packet[tcpStart + 2] << 8) + packet[tcpStart + 3]; |
|
|
const seqNum = ( |
|
|
(packet[tcpStart + 4] << 24) + |
|
|
(packet[tcpStart + 5] << 16) + |
|
|
(packet[tcpStart + 6] << 8) + |
|
|
packet[tcpStart + 7] |
|
|
) >>> 0; |
|
|
const ackNum = ( |
|
|
(packet[tcpStart + 8] << 24) + |
|
|
(packet[tcpStart + 9] << 16) + |
|
|
(packet[tcpStart + 10] << 8) + |
|
|
packet[tcpStart + 11] |
|
|
) >>> 0; |
|
|
|
|
|
const dataOffset = (packet[tcpStart + 12] >> 4) & 0x0F; |
|
|
const tcpHeaderLength = dataOffset * 4; |
|
|
|
|
|
|
|
|
const flags = packet[tcpStart + 13]; |
|
|
const isURG = (flags & 0x20) !== 0; |
|
|
const isACK = (flags & 0x10) !== 0; |
|
|
const isPSH = (flags & 0x08) !== 0; |
|
|
const isRST = (flags & 0x04) !== 0; |
|
|
const isSYN = (flags & 0x02) !== 0; |
|
|
const isFIN = (flags & 0x01) !== 0; |
|
|
|
|
|
const windowSize = (packet[tcpStart + 14] << 8) + packet[tcpStart + 15]; |
|
|
const checksum = (packet[tcpStart + 16] << 8) + packet[tcpStart + 17]; |
|
|
const urgentPointer = (packet[tcpStart + 18] << 8) + packet[tcpStart + 19]; |
|
|
|
|
|
|
|
|
const dataOffsetBytes = tcpHeaderLength; |
|
|
|
|
|
return { |
|
|
sourcePort, |
|
|
destPort, |
|
|
seqNum, |
|
|
ackNum, |
|
|
tcpHeaderLength, |
|
|
isURG, |
|
|
isACK, |
|
|
isPSH, |
|
|
isRST, |
|
|
isSYN, |
|
|
isFIN, |
|
|
windowSize, |
|
|
checksum, |
|
|
urgentPointer, |
|
|
dataOffsetBytes, |
|
|
flags |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function constructTCPPacket(options) { |
|
|
const { |
|
|
sourcePort, |
|
|
destPort, |
|
|
seqNum, |
|
|
ackNum, |
|
|
isACK = false, |
|
|
isSYN = false, |
|
|
isFIN = false, |
|
|
isRST = false, |
|
|
windowSize = 65535, |
|
|
data = Buffer.alloc(0) |
|
|
} = options; |
|
|
|
|
|
|
|
|
const tcpHeaderLength = 20; |
|
|
const packetLength = tcpHeaderLength + data.length; |
|
|
const packet = Buffer.alloc(packetLength); |
|
|
|
|
|
|
|
|
packet.writeUInt16BE(sourcePort, 0); |
|
|
packet.writeUInt16BE(destPort, 2); |
|
|
|
|
|
|
|
|
packet.writeUInt32BE(seqNum, 4); |
|
|
packet.writeUInt32BE(ackNum, 8); |
|
|
|
|
|
|
|
|
packet[12] = (5 << 4) | 0; |
|
|
|
|
|
|
|
|
let flags = 0; |
|
|
if (isACK) flags |= 0x10; |
|
|
if (isSYN) flags |= 0x02; |
|
|
if (isFIN) flags |= 0x01; |
|
|
if (isRST) flags |= 0x04; |
|
|
packet[13] = flags; |
|
|
|
|
|
|
|
|
packet.writeUInt16BE(windowSize, 14); |
|
|
|
|
|
|
|
|
packet.writeUInt16BE(0, 16); |
|
|
packet.writeUInt16BE(0, 18); |
|
|
|
|
|
|
|
|
if (data.length > 0) { |
|
|
data.copy(packet, tcpHeaderLength); |
|
|
} |
|
|
|
|
|
return packet; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isSYNPacket(tcpHeader) { |
|
|
return tcpHeader.isSYN && !tcpHeader.isACK; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isFINPacket(tcpHeader) { |
|
|
return tcpHeader.isFIN; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isRSTPacket(tcpHeader) { |
|
|
return tcpHeader.isRST; |
|
|
} |
|
|
|
|
|
module.exports = { |
|
|
parseTCPHeader, |
|
|
constructTCPPacket, |
|
|
isSYNPacket, |
|
|
isFINPacket, |
|
|
isRSTPacket |
|
|
}; |