use std::net::Ipv4Addr;
pub fn ipv4_header_checksum(header: &[u8]) -> u16 {
let mut sum: u32 = 0;
let mut i = 0;
while i + 1 < header.len() {
if i != 10 {
sum += u32::from(u16::from_be_bytes([header[i], header[i + 1]]));
}
i += 2;
}
while sum > 0xFFFF {
sum = (sum & 0xFFFF) + (sum >> 16);
}
!sum as u16
}
pub(super) fn udp_checksum(src_ip: Ipv4Addr, dst_ip: Ipv4Addr, udp_segment: &[u8]) -> u16 {
let mut sum: u32 = 0;
let src = src_ip.octets();
let dst = dst_ip.octets();
sum += u32::from(u16::from_be_bytes([src[0], src[1]]));
sum += u32::from(u16::from_be_bytes([src[2], src[3]]));
sum += u32::from(u16::from_be_bytes([dst[0], dst[1]]));
sum += u32::from(u16::from_be_bytes([dst[2], dst[3]]));
sum += 17u32; sum += udp_segment.len() as u32;
let mut i = 0;
while i + 1 < udp_segment.len() {
if i != 6 {
sum += u32::from(u16::from_be_bytes([udp_segment[i], udp_segment[i + 1]]));
}
i += 2;
}
if i < udp_segment.len() {
sum += u32::from(udp_segment[i]) << 8;
}
while sum > 0xFFFF {
sum = (sum & 0xFFFF) + (sum >> 16);
}
let result = !sum as u16;
if result == 0 { 0xFFFF } else { result }
}
pub fn tcp_checksum(src_ip: Ipv4Addr, dst_ip: Ipv4Addr, tcp_segment: &[u8]) -> u16 {
let mut sum: u32 = 0;
let src = src_ip.octets();
let dst = dst_ip.octets();
sum += u32::from(u16::from_be_bytes([src[0], src[1]]));
sum += u32::from(u16::from_be_bytes([src[2], src[3]]));
sum += u32::from(u16::from_be_bytes([dst[0], dst[1]]));
sum += u32::from(u16::from_be_bytes([dst[2], dst[3]]));
sum += 6u32; sum += tcp_segment.len() as u32;
let mut i = 0;
while i + 1 < tcp_segment.len() {
if i != 16 {
sum += u32::from(u16::from_be_bytes([tcp_segment[i], tcp_segment[i + 1]]));
}
i += 2;
}
if i < tcp_segment.len() {
sum += u32::from(tcp_segment[i]) << 8;
}
while sum > 0xFFFF {
sum = (sum & 0xFFFF) + (sum >> 16);
}
!sum as u16
}