1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use std::net::Ipv4Addr;
use xenet_packet::icmp::echo_request::MutableEchoRequestPacket;
use xenet_packet::icmp::IcmpType;
use xenet_packet::icmp::ICMPV4_HEADER_LEN;
use xenet_packet::Packet;

/// Build ICMP packet.
pub(crate) fn build_icmp_echo_packet(icmp_packet: &mut MutableEchoRequestPacket) {
    icmp_packet.set_icmp_type(IcmpType::EchoRequest);
    icmp_packet.set_sequence_number(rand::random::<u16>());
    icmp_packet.set_identifier(rand::random::<u16>());
    let icmp_check_sum = xenet_packet::util::checksum(&icmp_packet.packet(), 1);
    icmp_packet.set_checksum(icmp_check_sum);
}

/// ICMP Packet Builder.
#[derive(Clone, Debug)]
pub struct IcmpPacketBuilder {
    /// Source IPv4 address.
    pub src_ip: Ipv4Addr,
    /// Destination IPv4 address.
    pub dst_ip: Ipv4Addr,
    /// ICMP type.
    pub icmp_type: IcmpType,
    /// ICMP sequence number.
    pub sequence_number: Option<u16>,
    /// ICMP identifier.
    pub identifier: Option<u16>,
}

impl IcmpPacketBuilder {
    /// Constructs a new IcmpPacketBuilder.
    pub fn new(src_ip: Ipv4Addr, dst_ip: Ipv4Addr) -> IcmpPacketBuilder {
        IcmpPacketBuilder {
            src_ip: src_ip,
            dst_ip: dst_ip,
            icmp_type: IcmpType::EchoRequest,
            sequence_number: None,
            identifier: None,
        }
    }
    /// Build ICMP packet and return bytes.
    pub fn build(&self) -> Vec<u8> {
        let buffer: &mut [u8] = &mut [0u8; ICMPV4_HEADER_LEN];
        let mut icmp_packet = MutableEchoRequestPacket::new(buffer).unwrap();
        icmp_packet.set_icmp_type(self.icmp_type);
        if let Some(sequence_number) = self.sequence_number {
            icmp_packet.set_sequence_number(sequence_number);
        } else {
            icmp_packet.set_sequence_number(rand::random::<u16>());
        }
        if let Some(identifier) = self.identifier {
            icmp_packet.set_identifier(identifier);
        } else {
            icmp_packet.set_identifier(rand::random::<u16>());
        }
        let icmp_check_sum = xenet_packet::util::checksum(&icmp_packet.packet(), 1);
        icmp_packet.set_checksum(icmp_check_sum);
        icmp_packet.packet().to_vec()
    }
}