s2w / src /utils /tcpUtils.js
dvc890's picture
Upload 11 files
3c8ff75 verified
// tcpUtils.js
/**
* 解析TCP头部信息
* @param {Buffer} packet - IP数据包(包含TCP负载)
* @param {number} ipHeaderLength - IP头部长度
* @returns {Object} TCP头部信息
*/
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; // TCP头部长度(以4字节为单位)
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
};
}
/**
* 构造TCP数据包
* @param {Object} options - TCP数据包选项
* @returns {Buffer} 构造的TCP数据包
*/
function constructTCPPacket(options) {
const {
sourcePort,
destPort,
seqNum,
ackNum,
isACK = false,
isSYN = false,
isFIN = false,
isRST = false,
windowSize = 65535,
data = Buffer.alloc(0)
} = options;
// TCP头部最小长度为20字节
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);
// 设置数据偏移和保留位(数据偏移为5,表示20字节头部)
packet[12] = (5 << 4) | 0; // 数据偏移=5,保留位=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);
// 校验和和紧急指针设为0(简化处理)
packet.writeUInt16BE(0, 16); // 校验和
packet.writeUInt16BE(0, 18); // 紧急指针
// 添加数据
if (data.length > 0) {
data.copy(packet, tcpHeaderLength);
}
return packet;
}
/**
* 检查是否为TCP SYN包(连接请求)
* @param {Object} tcpHeader - TCP头部信息
* @returns {boolean} 是否为SYN包
*/
function isSYNPacket(tcpHeader) {
return tcpHeader.isSYN && !tcpHeader.isACK;
}
/**
* 检查是否为TCP FIN包(连接终止)
* @param {Object} tcpHeader - TCP头部信息
* @returns {boolean} 是否为FIN包
*/
function isFINPacket(tcpHeader) {
return tcpHeader.isFIN;
}
/**
* 检查是否为TCP RST包(连接重置)
* @param {Object} tcpHeader - TCP头部信息
* @returns {boolean} 是否为RST包
*/
function isRSTPacket(tcpHeader) {
return tcpHeader.isRST;
}
module.exports = {
parseTCPHeader,
constructTCPPacket,
isSYNPacket,
isFINPacket,
isRSTPacket
};