在 Rust 中计算 UDP 校验和?
Calculate UDP Checksum in Rust?
我正在尝试手动构建数据包,但在计算正确的 UDP 校验和时遇到了问题。有人可以告诉我我在下面的代码中做错了什么吗?传入的数据包是要发送的完整数据包,其中 UDP 校验和的占位符当前为 0x0000,但我对 psuedoheader、udpheader 和 udp 有效负载求和,但根据 wireshark 我的UDP 校验和不正确。 (例如,我的:0x9f4c 与 Wireshark:0x2b7b)
fn udp_checksum (packet: &Vec<u8>) -> [u8; 2] {
let mut idx = 0;
let mut idx_end = 2;
let mut payload = &packet[42..];
let payload_len = payload.len();
if payload_len % 2 != 0 {
payload.to_vec().push(0);
}
let source_ip_1 = BigEndian::read_u16(&packet[26..28]); //source ip 1 of 2
let source_ip_2 = BigEndian::read_u16(&packet[28..30]); //source ip 2 of 2
let dest_ip_1 = BigEndian::read_u16(&packet[30..32]); //dest ip 1 of 2
let dest_ip_2 = BigEndian::read_u16(&packet[32..34]); //dest ip 2 of 2
let udp_len = BigEndian::read_u16(&packet[38..40]);
let source_port = BigEndian::read_u16(&packet[34..36]);
let dest_port = BigEndian::read_u16(&packet[36..38]);
let mut header_sum = UDP_PROTO as u32 + source_ip_1 as u32 + source_ip_2 as u32 + dest_ip_1 as u32 + dest_ip_2 as u32 + udp_len as u32 + source_port as u32 + dest_port as u32 + udp_len as u32;
// println!("Payload Len: {:?}", &payload.len());
// println!("Payload: {:?}", &payload);
// println!("First Payload Slice: {:?}", &payload[idx..idx_end]);
// println!("First BE U32: {:?}", BigEndian::read_u16(&payload[idx..idx_end]) as u32);
while idx < &payload.len() - 2 {
header_sum += BigEndian::read_u16(&payload[idx..idx_end]) as u32;
println!("Header Sum: {:0x?}", &header_sum);
idx += 2;
idx_end += 2;
}
while header_sum > 0xffff {
header_sum -= 0xffff;
header_sum += 1;
}
let udp_csum = 0xffff - (header_sum as u16);
let csum_one: u8 = header_sum as u8;
let csum_two: u8 = (header_sum >> 8) as u8;
println!("Calculated CSUM: {:?}", udp_csum);
println!("Checksum: {:0x}{:0x}", csum_one, csum_two);
return [csum_one, csum_two];
}```
这可能只是部分解决问题的方法。
payload.to_vec()
创建一个新向量。
扩展它对 payload
.
没有影响
使 payload
可变将在必要时启用对扩展矢量的处理。
这是一个最小的例子。
fn main() {
let v1 = vec![9, 1, 2, 3];
let mut v2 = Vec::new(); // empty for now
let mut sl = &v1[1..]; // could be reassigned to v2
println!("before v1: {:?}", v1);
println!("before v2: {:?}", v2);
println!("before sl: {:?}", sl);
if sl.len() % 2 != 0 {
v2 = sl.to_vec();
v2.push(0);
sl = &v2[..];
}
println!("after v1: {:?}", v1);
println!("after v2: {:?}", v2);
println!("after sl: {:?}", sl);
}
/*
before v1: [9, 1, 2, 3]
before v2: []
before sl: [1, 2, 3]
after v1: [9, 1, 2, 3]
after v2: [1, 2, 3, 0]
after sl: [1, 2, 3, 0]
*/
避免复制的另一种解决方案是提前一个字节停止循环(如果 payload.len()
是奇数),然后处理剩余的字节。
我正在尝试手动构建数据包,但在计算正确的 UDP 校验和时遇到了问题。有人可以告诉我我在下面的代码中做错了什么吗?传入的数据包是要发送的完整数据包,其中 UDP 校验和的占位符当前为 0x0000,但我对 psuedoheader、udpheader 和 udp 有效负载求和,但根据 wireshark 我的UDP 校验和不正确。 (例如,我的:0x9f4c 与 Wireshark:0x2b7b)
fn udp_checksum (packet: &Vec<u8>) -> [u8; 2] {
let mut idx = 0;
let mut idx_end = 2;
let mut payload = &packet[42..];
let payload_len = payload.len();
if payload_len % 2 != 0 {
payload.to_vec().push(0);
}
let source_ip_1 = BigEndian::read_u16(&packet[26..28]); //source ip 1 of 2
let source_ip_2 = BigEndian::read_u16(&packet[28..30]); //source ip 2 of 2
let dest_ip_1 = BigEndian::read_u16(&packet[30..32]); //dest ip 1 of 2
let dest_ip_2 = BigEndian::read_u16(&packet[32..34]); //dest ip 2 of 2
let udp_len = BigEndian::read_u16(&packet[38..40]);
let source_port = BigEndian::read_u16(&packet[34..36]);
let dest_port = BigEndian::read_u16(&packet[36..38]);
let mut header_sum = UDP_PROTO as u32 + source_ip_1 as u32 + source_ip_2 as u32 + dest_ip_1 as u32 + dest_ip_2 as u32 + udp_len as u32 + source_port as u32 + dest_port as u32 + udp_len as u32;
// println!("Payload Len: {:?}", &payload.len());
// println!("Payload: {:?}", &payload);
// println!("First Payload Slice: {:?}", &payload[idx..idx_end]);
// println!("First BE U32: {:?}", BigEndian::read_u16(&payload[idx..idx_end]) as u32);
while idx < &payload.len() - 2 {
header_sum += BigEndian::read_u16(&payload[idx..idx_end]) as u32;
println!("Header Sum: {:0x?}", &header_sum);
idx += 2;
idx_end += 2;
}
while header_sum > 0xffff {
header_sum -= 0xffff;
header_sum += 1;
}
let udp_csum = 0xffff - (header_sum as u16);
let csum_one: u8 = header_sum as u8;
let csum_two: u8 = (header_sum >> 8) as u8;
println!("Calculated CSUM: {:?}", udp_csum);
println!("Checksum: {:0x}{:0x}", csum_one, csum_two);
return [csum_one, csum_two];
}```
这可能只是部分解决问题的方法。
payload.to_vec()
创建一个新向量。
扩展它对 payload
.
使 payload
可变将在必要时启用对扩展矢量的处理。
这是一个最小的例子。
fn main() {
let v1 = vec![9, 1, 2, 3];
let mut v2 = Vec::new(); // empty for now
let mut sl = &v1[1..]; // could be reassigned to v2
println!("before v1: {:?}", v1);
println!("before v2: {:?}", v2);
println!("before sl: {:?}", sl);
if sl.len() % 2 != 0 {
v2 = sl.to_vec();
v2.push(0);
sl = &v2[..];
}
println!("after v1: {:?}", v1);
println!("after v2: {:?}", v2);
println!("after sl: {:?}", sl);
}
/*
before v1: [9, 1, 2, 3]
before v2: []
before sl: [1, 2, 3]
after v1: [9, 1, 2, 3]
after v2: [1, 2, 3, 0]
after sl: [1, 2, 3, 0]
*/
避免复制的另一种解决方案是提前一个字节停止循环(如果 payload.len()
是奇数),然后处理剩余的字节。