// 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 };