84 lines
3.3 KiB
Rust
84 lines
3.3 KiB
Rust
|
|
enum IpType {
|
|
ICMP = 0x01,
|
|
TCP = 0x06,
|
|
UDP = 0x11,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct IpPackage {
|
|
version: u8, // 4bits
|
|
hlen: u8, // 4bits,
|
|
type_of_service: u8, // 8bits
|
|
total_length: u16, // 16bits
|
|
identification: u16, // 16bits
|
|
flags: u8, // 4bits
|
|
fragment_offset: u16, // 12 bits
|
|
ttl: u8, // 8bits
|
|
protocol: u8, // 8bits
|
|
header_checksum: u16, // 16bits
|
|
source_ip_address: [u8; 4], // 32bits
|
|
destination_ip_address: [u8; 4], // 32bits
|
|
ip_options: [u8; 3], // 24bits
|
|
data: Vec<u8>,
|
|
}
|
|
|
|
impl IpPackage {
|
|
fn parse(bytes: &[u8]) -> Result<Self, String> {
|
|
if bytes.len() < 24 {
|
|
return Err("Length < 24".to_owned());
|
|
}
|
|
let mut bytes_iter = bytes.iter();
|
|
let ver_hlen = bytes_iter.next().unwrap();
|
|
let version = (ver_hlen >> 4) & 0x0f as u8;
|
|
let hlen = ver_hlen & 0x0f as u8;
|
|
let type_of_service = *bytes_iter.next().unwrap();
|
|
let total_length_bytes = [*bytes_iter.next().unwrap(), *bytes_iter.next().unwrap()];
|
|
let total_length = u16::from_be_bytes(total_length_bytes);
|
|
let identification_bytes = [*bytes_iter.next().unwrap(), *bytes_iter.next().unwrap()];
|
|
let identification = u16::from_be_bytes(identification_bytes);
|
|
let tmp = *bytes_iter.next().unwrap();
|
|
let flags = (tmp >> 4) & 0x0f as u8;
|
|
let fragment_offset_bytes = [tmp & 0x0f, *bytes_iter.next().unwrap()];
|
|
let fragment_offset = u16::from_be_bytes(fragment_offset_bytes);
|
|
let ttl = *bytes_iter.next().unwrap();
|
|
let protocol = *bytes_iter.next().unwrap();
|
|
let header_checksum_bytes = [*bytes_iter.next().unwrap(), *bytes_iter.next().unwrap()];
|
|
let header_checksum = u16::from_be_bytes(header_checksum_bytes);
|
|
let source_ip_address = [
|
|
*bytes_iter.next().unwrap(), *bytes_iter.next().unwrap(),
|
|
*bytes_iter.next().unwrap(), *bytes_iter.next().unwrap()
|
|
];
|
|
let destination_ip_address = [
|
|
*bytes_iter.next().unwrap(), *bytes_iter.next().unwrap(),
|
|
*bytes_iter.next().unwrap(), *bytes_iter.next().unwrap()
|
|
];
|
|
let ip_options = [
|
|
*bytes_iter.next().unwrap(), *bytes_iter.next().unwrap(), *bytes_iter.next().unwrap()
|
|
];
|
|
bytes_iter.next(); // padding
|
|
let data = bytes[24..].to_vec();
|
|
|
|
Ok(Self{
|
|
version, hlen, type_of_service, total_length,
|
|
identification, flags, fragment_offset, ttl, protocol,
|
|
header_checksum, source_ip_address, destination_ip_address, ip_options, data,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_ip_package_parse() {
|
|
let icmp_ip_package = vec![
|
|
0x45, 0x00, 0x00, 0x54, 0x36, 0x55, 0x40, 0x00, 0x40, 0x01, 0x30, 0x6D, 0xC0, 0xA8,
|
|
0x03, 0x2F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x6C, 0x47, 0x08, 0xBF, 0x00, 0x01,
|
|
0xE8, 0x4D, 0xA3, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x33, 0x78, 0x05, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
|
|
0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
|
|
0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
|
|
];
|
|
|
|
let package = IpPackage::parse(&icmp_ip_package).unwrap();
|
|
println!("{:#?}", package);
|
|
assert_eq!(0x04, package.version);
|
|
} |