diff options
| author | luwenpeng <[email protected]> | 2023-09-08 11:32:10 +0800 |
|---|---|---|
| committer | luwenpeng <[email protected]> | 2023-09-08 11:43:05 +0800 |
| commit | 92dbc9420833c3c4d716eaea3f7dae7c8638653d (patch) | |
| tree | fdc904548a3293279a44f3eadf6ae04a1ca4d155 /src/protocol | |
| parent | 610ffd61eb231e8ddab397bb6a4920137da27d4e (diff) | |
[feature] Support ICMP Decode
Diffstat (limited to 'src/protocol')
| -rw-r--r-- | src/protocol/icmp.rs | 147 | ||||
| -rw-r--r-- | src/protocol/mod.rs | 3 |
2 files changed, 149 insertions, 1 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); + } +} diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 044481a..ba06b66 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -7,4 +7,5 @@ pub mod udp; pub mod tcp; pub mod dns; pub mod http; -pub mod vlan;
\ No newline at end of file +pub mod vlan; +pub mod icmp;
\ No newline at end of file |
