tiny_ping/
icmp.rs

1use std::net::IpAddr;
2
3use crate::{EchoRequest as ER2, IcmpV4, IpV4Packet, ER1};
4
5use crate::error::{Error, Result};
6
7#[derive(Debug)]
8pub struct EchoRequest {
9    pub destination: IpAddr,
10    pub ident: u16,
11    pub seq_cnt: u16,
12    pub size: usize,
13}
14
15impl EchoRequest {
16    pub fn new(destination: IpAddr, ident: u16, seq_cnt: u16, size: usize) -> Self {
17        EchoRequest {
18            destination,
19            ident,
20            seq_cnt,
21            size,
22        }
23    }
24
25    pub fn encode(&self) -> Result<Vec<u8>> {
26        match self.destination {
27            IpAddr::V4(_) => self.encode_icmp_v4(),
28            IpAddr::V6(_) => self.encode_icmp_v6(),
29        }
30    }
31
32    /// Encodes as an ICMPv4 EchoRequest.
33    fn encode_icmp_v4(&self) -> Result<Vec<u8>> {
34        let req = ER2 {
35            ident: self.ident,
36            seq_cnt: self.seq_cnt,
37        };
38        let mut buffer = vec![0; 8 + self.size]; // 8 bytes of header, then payload
39        let payload = vec![0; self.size];
40        req.encode::<IcmpV4>(&mut buffer, &payload)
41    }
42
43    /// Encodes as an ICMPv6 EchoRequest.
44    fn encode_icmp_v6(&self) -> Result<Vec<u8>> {
45        Err(Error::Unimplemented)
46    }
47}
48
49/// `EchoReply` struct, which contains some packet information.
50#[derive(Debug)]
51pub struct EchoReply {
52    /// IP Time To Live for outgoing packets. Present for ICMPv4 replies,
53    /// absent for ICMPv6 replies.
54    pub ttl: Option<u8>,
55    /// Source address of ICMP packet.
56    pub source: IpAddr,
57    /// Sequence of ICMP packet.
58    pub sequence: u16,
59    /// Identifier of ICMP packet.
60    pub identifier: u16,
61    /// Size of ICMP packet.
62    pub size: usize,
63}
64
65impl EchoReply {
66    /// Unpack IP packets received from socket as `EchoReply` struct.
67    pub fn decode(addr: IpAddr, buf: &[u8]) -> Result<EchoReply> {
68        match addr {
69            IpAddr::V4(_) => decode_icmpv4(addr, buf),
70            IpAddr::V6(_) => decode_icmpv6(addr, buf),
71        }
72    }
73}
74
75/// Decodes an ICMPv4 packet received from an IPv4 raw socket
76fn decode_icmpv4(addr: IpAddr, buf: &[u8]) -> Result<EchoReply> {
77    let ipv4_decoded = IpV4Packet::decode(buf)?;
78    let icmp_decoded = ER1::decode::<IcmpV4>(ipv4_decoded.data)?;
79    Ok(EchoReply {
80        ttl: None,
81        source: addr,
82        sequence: icmp_decoded.seq_cnt,
83        identifier: icmp_decoded.ident,
84        size: icmp_decoded.payload.len(),
85    })
86}
87
88/// Decodes an ICMPv6 packet received from an IPv6 raw socket
89fn decode_icmpv6(_addr: IpAddr, _buf: &[u8]) -> Result<EchoReply> {
90    Err(Error::Unimplemented)
91}