File size: 4,044 Bytes
3c8ff75 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
// 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
}; |