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

固定长度UDP报文无循环校验和计算问题排查求助

UDP固定13字节负载无循环校验和计算错误排查

你的代码存在三个核心问题,导致校验和计算结果不符合规范,以下是具体分析和修正方案:

问题1:计算时未将UDP校验和字段置0

UDP校验和规范明确要求,计算校验和时必须将UDP首部中的校验和字段先设为0。你的测试代码直接使用etherparse生成的已包含正确校验和的报文作为输入,相当于把正确的校验和值也加入了累加计算,最终结果自然与预期不符。

问题2:遗漏UDP长度字段的累加

UDP校验和的计算范围包含UDP首部的长度字段(占2字节),你的代码只累加了源端口、目的端口,完全漏掉了该字段,导致累加值缺失部分关键数据。

问题3:奇数长度负载的最后一字节处理错误

负载长度为13字节(奇数),按规范需要在末尾补一个0字节,组成最后一个16位大端序字(高字节为0,低字节为原最后一字节)进行累加。你的代码将最后一字节左移8位(当成高字节),完全颠倒了字节序,导致该部分累加值错误。


修正后的代码

use etherparse::PacketBuilder;

const SRC_IP: usize = 12;
const DST_IP: usize = 16;

const UDP_START: usize = 20;
const SRC_PORT: usize = 0;
const DST_PORT: usize = 2;
const LEN: usize = 4;
const CHECK: usize = 6;

const IP_HEADER_LEN: u32 = 20;
const UDP_HEADER_LEN: u32 = 8;
const PAYLOAD_LEN: u32 = 13;

const PAYLOAD_START: usize = IP_HEADER_LEN as usize + UDP_HEADER_LEN as usize;

fn my_checksum(mut packet: [u8; (IP_HEADER_LEN + UDP_HEADER_LEN + PAYLOAD_LEN) as usize]) -> [u8; 2] {
    // 计算校验和前,将UDP校验和字段置0,符合规范要求
    packet[UDP_START + CHECK] = 0;
    packet[UDP_START + CHECK + 1] = 0;

    let mut sum: u32 = UDP_HEADER_LEN + PAYLOAD_LEN + 17; // 17 = UDP协议号
    // 源IP
    sum += (packet[SRC_IP] as u32) << 8 | (packet[SRC_IP + 1] as u32);
    sum += (packet[SRC_IP + 2] as u32) << 8 | (packet[SRC_IP + 3] as u32);
    // 目的IP
    sum += (packet[DST_IP] as u32) << 8 | (packet[DST_IP + 1] as u32);
    sum += (packet[DST_IP + 2] as u32) << 8 | (packet[DST_IP + 3] as u32);
    // 源端口
    sum += (packet[UDP_START + SRC_PORT] as u32) << 8 | packet[UDP_START + SRC_PORT + 1] as u32;
    // 目的端口
    sum += (packet[UDP_START + DST_PORT] as u32) << 8 | packet[UDP_START + DST_PORT + 1] as u32;
    // 新增:UDP长度字段累加
    sum += (packet[UDP_START + LEN] as u32) << 8 | packet[UDP_START + LEN + 1] as u32;
    // 负载
    sum += (packet[PAYLOAD_START + 0] as u32) << 8 | packet[PAYLOAD_START + 1] as u32;
    sum += (packet[PAYLOAD_START + 2] as u32) << 8 | packet[PAYLOAD_START + 3] as u32;
    sum += (packet[PAYLOAD_START + 4] as u32) << 8 | packet[PAYLOAD_START + 5] as u32;
    sum += (packet[PAYLOAD_START + 6] as u32) << 8 | packet[PAYLOAD_START + 7] as u32;
    sum += (packet[PAYLOAD_START + 8] as u32) << 8 | packet[PAYLOAD_START + 9] as u32;
    sum += (packet[PAYLOAD_START + 10] as u32) << 8 | packet[PAYLOAD_START + 11] as u32;
    // 修正:最后一个奇数字节处理,补0作为高字节,原字节作为低字节
    sum += packet[PAYLOAD_START + 12] as u32;

    // 处理溢出
    sum = (sum & 0xffff) + (sum >> 16);
    sum = (sum & 0xffff) + (sum >> 16);

    let sum = !(sum as u16);
    sum.to_be_bytes()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_packet() {
        // Build packet using etherparse
        let builder = PacketBuilder::ipv4([192, 168, 1, 1], [192, 168, 1, 2], 20).udp(10000, 5000);
        let payload = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];

        let mut result = Vec::<u8>::with_capacity(builder.size(payload.len()));
        builder.write(&mut result, &payload).unwrap();

        println!("{:?}", result);
        assert_eq!(
            [result[UDP_START + CHECK], result[UDP_START + CHECK + 1]],
            my_checksum(result.try_into().unwrap())
        );
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 23:05:55