
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);
}