summaryrefslogtreecommitdiff
path: root/src/protocol/icmp.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol/icmp.rs')
-rw-r--r--src/protocol/icmp.rs147
1 files changed, 147 insertions, 0 deletions
diff --git a/src/protocol/icmp.rs b/src/protocol/icmp.rs
new file mode 100644
index 0000000..c1352d5
--- /dev/null
+++ b/src/protocol/icmp.rs
@@ -0,0 +1,147 @@
+use crate::protocol::codec::Decode;
+use nom::number;
+use nom::IResult;
+
+/******************************************************************************
+ * Struct
+ ******************************************************************************/
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum IcmpType {
+ EchoReply,
+ DestinationUnreachable,
+ SourceQuench,
+ Redirect,
+ EchoRequest,
+ RouterAdvertisement,
+ RouterSolicitation,
+ TimeExceeded,
+ ParameterProblem,
+ Timestamp,
+ TimestampReply,
+ InformationRequest,
+ InformationReply,
+ AddressMaskRequest,
+ AddressMaskReply,
+ Traceroute,
+ Other(u8),
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct IcmpHeader {
+ pub icmp_type: IcmpType,
+ pub icmp_code: u8,
+ pub icmp_checksum: u16,
+ pub icmp_payload: Vec<u8>,
+}
+
+/******************************************************************************
+ * API
+ ******************************************************************************/
+
+impl From<u8> for IcmpType {
+ fn from(raw: u8) -> Self {
+ match raw {
+ 0 => IcmpType::EchoReply,
+ 3 => IcmpType::DestinationUnreachable,
+ 4 => IcmpType::SourceQuench,
+ 5 => IcmpType::Redirect,
+ 8 => IcmpType::EchoRequest,
+ 9 => IcmpType::RouterAdvertisement,
+ 10 => IcmpType::RouterSolicitation,
+ 11 => IcmpType::TimeExceeded,
+ 12 => IcmpType::ParameterProblem,
+ 13 => IcmpType::Timestamp,
+ 14 => IcmpType::TimestampReply,
+ 15 => IcmpType::InformationRequest,
+ 16 => IcmpType::InformationReply,
+ 17 => IcmpType::AddressMaskRequest,
+ 18 => IcmpType::AddressMaskReply,
+ 30 => IcmpType::Traceroute,
+ other => IcmpType::Other(other),
+ }
+ }
+}
+
+impl Decode for IcmpHeader {
+ type Iterm = IcmpHeader;
+ fn decode(input: &[u8]) -> IResult<&[u8], IcmpHeader> {
+ let (input, icmp_type) = number::streaming::be_u8(input)?;
+ let (input, icmp_code) = number::streaming::be_u8(input)?;
+ let (input, icmp_checksum) = number::streaming::be_u16(input)?;
+ let (input, icmp_payload) = nom::bytes::streaming::take(4u8)(input)?;
+
+ Ok((
+ input,
+ IcmpHeader {
+ icmp_type: icmp_type.into(),
+ icmp_code,
+ icmp_checksum,
+ icmp_payload: icmp_payload.to_vec(),
+ },
+ ))
+ }
+}
+
+/******************************************************************************
+ * TEST
+ ******************************************************************************/
+
+#[cfg(test)]
+mod tests {
+ use super::IcmpHeader;
+ use crate::protocol::{codec::Decode, icmp::IcmpType};
+ const LAST_SLICE: &'static [u8] = &[
+ 0x96, 0xb5, 0xe9, 0x5e, 0x00, 0x00, 0x00, 0x00, 0xac, 0xe6, 0x02, 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,
+ ];
+
+ #[test]
+ fn icmp_header_decode() {
+ /*
+ * Internet Control Message Protocol
+ * Type: 8 (Echo (ping) request)
+ * Code: 0
+ * Checksum: 0xab05 [correct]
+ * [Checksum Status: Good]
+ * Identifier (BE): 24363 (0x5f2b)
+ * Identifier (LE): 11103 (0x2b5f)
+ * Sequence Number (BE): 1 (0x0001)
+ * Sequence Number (LE): 256 (0x0100)
+ * [Response frame: 2]
+ * Timestamp from icmp data: Jun 17, 2020 14:17:58.000000000 CST
+ * [Timestamp from icmp data (relative): 0.055548000 seconds]
+ * Data (48 bytes)
+ * Data: ace6020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b…
+ * [Length: 48]
+ */
+ let bytes = [
+ 0x08, 0x00, 0xab, 0x05, 0x5f, 0x2b, 0x00, 0x01, /* Payload */
+ 0x96, 0xb5, 0xe9, 0x5e, 0x00, 0x00, 0x00, 0x00, 0xac, 0xe6, 0x02, 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 expectation = IcmpHeader {
+ icmp_type: IcmpType::EchoRequest,
+ icmp_code: 0,
+ icmp_checksum: 0xab05,
+ icmp_payload: vec![0x5f, 0x2b, 0x00, 0x01],
+ };
+
+ assert_eq!(IcmpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let vlan = IcmpHeader::decode(&bytes);
+ if let Ok((payload, header)) = vlan {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+}