我需要为固定长度的数据包编写一个无循环版本的 UDP 标头计算。我的数据包始终具有 13 字节的有效负载。我为其编写了以下测试程序,但由于某种原因我无法从阅读 UDP 校验和规范中得到正确的答案。有什么想法问题出在哪里吗?
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(packet: [u8; (IP_HEADER_LEN + UDP_HEADER_LEN + PAYLOAD_LEN) as usize]) -> [u8; 2] {
let mut sum: u32 = UDP_HEADER_LEN + PAYLOAD_LEN + 17; // 17 = UDP protocol number
// Source 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);
// Destination 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);
// Source PORT
sum += (packet[UDP_START + SRC_PORT] as u32) << 8 | packet[UDP_START + SRC_PORT + 1] as u32;
// Destination PORT
sum += (packet[UDP_START + DST_PORT] as u32) << 8 | packet[UDP_START + DST_PORT + 1] as u32;
// Payload
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;
sum += (packet[PAYLOAD_START + 12] as u32) << 8;
// We need at most 2 rounds for overflow clearing for a packet less than 64 bytes.
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())
);
}
}
问题是长度同时存在于伪标头和 UDP 标头中,因此需要按照问题评论中的建议添加两次。