固定长度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
相关产品推荐
相关产品推荐

