You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IPv4首部校验和计算结果与Wireshark不一致问题排查

IPv4首部校验和计算错误的问题分析与修正

核心问题:字节序不匹配

IPv4协议规定所有多字节字段(如总长度、标识、校验和等)必须使用大端字节序(网络字节序),但你创建ByteBuffer时指定了ByteOrder.LITTLE_ENDIAN,这会导致所有多字节字段的字节顺序反转,直接让校验和计算结果完全错误。

比如totalLength值为1056,对应十六进制0x0420,大端序下buffer中存储的是0x04、0x20,但小端序会存储为0x20、0x04,计算时取这两个字节组成的16位字变成0x2004,而非正确的0x0420,最终求和结果必然偏差。

次要问题:校验和字段初始化

IPv4校验和计算要求校验和字段本身必须先置为0,如果你的checksum变量初始值非0,即便计算时跳过了该字段,buffer中残留的非0值也会影响后续验证逻辑(虽不是本次错误的直接原因,但必须修正)。

代码修正步骤

1. 修正ByteBuffer字节序

将ByteBuffer的字节序改为大端(默认即为大端,显式声明可避免歧义):

var tmpBuffer = ByteBuffer.allocate(getSizeInBytes()).order(ByteOrder.BIG_ENDIAN);

2. 初始化校验和字段为0

构造buffer时,先将校验和字段设为0:

tmpBuffer.putShort((short) 0); // 校验和字段必须先置0

3. 优化校验和计算逻辑(提升正确性)

调整进位处理逻辑,确保所有进位都被累加,同时简化取反操作:

private short computeChecksum(byte[] data) {
    int end = getSizeInBytes(); // =20
    int sum = 0;
    final int checksumStart = 10; // 校验和字段起始字节索引

    for (int i = 0; i < end; i += 2) {
        if (i == checksumStart) {
            continue; // 跳过校验和字段
        }
        // 组合成16位大端字:高字节左移8位 + 低字节
        int word = ((data[i] & 0xFF) << 8) | (data[i+1] & 0xFF);
        sum += word;
        // 循环处理进位,直到sum仅保留低16位
        while ((sum >> 16) != 0) {
            sum = (sum & 0xFFFF) + (sum >> 16);
        }
    }
    // 取反得到最终校验和
    return (short) ~sum;
}

验证结果

修正后重新计算,即可得到Wireshark显示的正确值0xdc5c。

内容的提问来源于stack exchange,提问作者Dmitry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:10:30