diff options
| -rw-r--r-- | src/main.rs | 3 | ||||
| -rw-r--r-- | src/packet/error.rs | 2 | ||||
| -rw-r--r-- | src/packet/packet.rs | 19 | ||||
| -rw-r--r-- | src/protocol/icmp.rs | 12 | ||||
| -rw-r--r-- | src/protocol/icmpv6.rs | 181 | ||||
| -rw-r--r-- | src/protocol/mod.rs | 3 | ||||
| -rw-r--r-- | src/protocol/vlan.rs | 4 |
7 files changed, 215 insertions, 9 deletions
diff --git a/src/main.rs b/src/main.rs index d4fc3ac..8ffdb9c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,6 +46,9 @@ fn trigger_packet_event( PacketEvent::ICMP_EVENT => { // TODO } + PacketEvent::ICMPV6_EVENT => { + // TODO + } } } } diff --git a/src/packet/error.rs b/src/packet/error.rs index 55523be..eda7e4c 100644 --- a/src/packet/error.rs +++ b/src/packet/error.rs @@ -20,6 +20,7 @@ pub enum PacketError { IncompleteUdpHeader, IncompleteTcpHeader, IncompleteIcmpHeader, + IncompleteIcmpv6Header, } impl core::fmt::Display for PacketError { @@ -40,6 +41,7 @@ impl core::fmt::Display for PacketError { PacketError::IncompleteUdpHeader => write!(f, "Incomplete UDP Header"), PacketError::IncompleteTcpHeader => write!(f, "Incomplete TCP Header"), PacketError::IncompleteIcmpHeader => write!(f, "Incomplete ICMP Header"), + PacketError::IncompleteIcmpv6Header => write!(f, "Incomplete ICMPv6 Header"), } } } diff --git a/src/packet/packet.rs b/src/packet/packet.rs index 1b4602c..84f75f1 100644 --- a/src/packet/packet.rs +++ b/src/packet/packet.rs @@ -3,6 +3,7 @@ use crate::protocol::codec::Decode; use crate::protocol::ethernet::EtherType; use crate::protocol::ethernet::EthernetFrame; use crate::protocol::icmp::IcmpHeader; +use crate::protocol::icmpv6::Icmpv6Header; use crate::protocol::ip::IPProtocol; use crate::protocol::ipv4::IPv4Header; use crate::protocol::ipv6::IPv6Header; @@ -22,6 +23,7 @@ pub enum Encapsulation<'a> { L4_TCP(TcpHeader, &'a [u8]), L4_UDP(UdpHeader, &'a [u8]), L4_ICMP(IcmpHeader, &'a [u8]), + L4_ICMPV6(Icmpv6Header, &'a [u8]), UNSUPPORTED(&'a [u8]), } @@ -43,6 +45,7 @@ pub enum PacketEvent { TCP_EVENT, UDP_EVENT, ICMP_EVENT, + ICMPV6_EVENT, } #[derive(Debug)] @@ -477,6 +480,22 @@ fn handle_l4<'a>( return Err(PacketError::IncompleteIcmpHeader); } } + IPProtocol::ICMP6 => { + let result = Icmpv6Header::decode(input); + if let Ok((payload, header)) = result { + dbg!(&header); + + packet + .encapsulation + .push(Encapsulation::L4_ICMPV6(header, payload)); + + packet.event.push(PacketEvent::L4_EVENT); + packet.event.push(PacketEvent::ICMPV6_EVENT); + return Ok(()); + } else { + return Err(PacketError::IncompleteIcmpv6Header); + } + } IPProtocol::UDP => { let result = UdpHeader::decode(input); if let Ok((payload, header)) = result { diff --git a/src/protocol/icmp.rs b/src/protocol/icmp.rs index c1352d5..314c3d7 100644 --- a/src/protocol/icmp.rs +++ b/src/protocol/icmp.rs @@ -32,7 +32,7 @@ pub struct IcmpHeader { pub icmp_type: IcmpType, pub icmp_code: u8, pub icmp_checksum: u16, - pub icmp_payload: Vec<u8>, + pub icmp_extended: Vec<u8>, } /****************************************************************************** @@ -69,7 +69,7 @@ impl Decode for 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)?; + let (input, icmp_extended) = nom::bytes::streaming::take(4u8)(input)?; Ok(( input, @@ -77,7 +77,7 @@ impl Decode for IcmpHeader { icmp_type: icmp_type.into(), icmp_code, icmp_checksum, - icmp_payload: icmp_payload.to_vec(), + icmp_extended: icmp_extended.to_vec(), }, )) } @@ -129,14 +129,14 @@ mod tests { icmp_type: IcmpType::EchoRequest, icmp_code: 0, icmp_checksum: 0xab05, - icmp_payload: vec![0x5f, 0x2b, 0x00, 0x01], + icmp_extended: 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 { + let result = IcmpHeader::decode(&bytes); + if let Ok((payload, header)) = result { println!("return: {:?}, payload: {}", header, payload.len()); } else { println!("return: Incomplete data"); diff --git a/src/protocol/icmpv6.rs b/src/protocol/icmpv6.rs new file mode 100644 index 0000000..837f2e6 --- /dev/null +++ b/src/protocol/icmpv6.rs @@ -0,0 +1,181 @@ +use crate::protocol::codec::Decode; +use nom::number; +use nom::IResult; + +/****************************************************************************** + * Struct + ******************************************************************************/ + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Icmpv6Type { + DestinationUnreachable, + PacketTooBig, + TimeExceeded, + ParameterProblem, + EchoRequest, + EchoReply, + MulticastListenerQuery, + MulticastListenerReport, + MulticastListenerDone, + RouterSolicitation, + RouterAdvertisement, + NeighborSolicitation, + NeighborAdvertisement, + RedirectMessage, + RouterRenumbering, + NodeInformationQuery, + NodeInformationResponse, + InverseNeighborDiscoverySolicitation, + InverseNeighborDiscoveryAdvertisement, + Version2MulticastListenerReport, + HomeAgentAddressDiscoveryRequest, + HomeAgentAddressDiscoveryReply, + MobilePrefixSolicitation, + MobilePrefixAdvertisement, + CertificationPathSolicitation, + CertificationPathAdvertisement, + MulticastRouterAdvertisement, + MulticastRouterSolicitation, + MulticastRouterTermination, + Fmipv6Messages, + RplControlMessage, + Ilnpv6LocatorUpdateMessage, + DuplicateAddressRequest, + DuplicateAddressConfirmation, + MplControlMessage, + ExtendedEchoRequest, + ExtendedEchoReply, + Other(u8), +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Icmpv6Header { + pub icmp_type: Icmpv6Type, + pub icmp_code: u8, + pub checksum: u16, +} + +/****************************************************************************** + * API + ******************************************************************************/ + +impl From<u8> for Icmpv6Type { + fn from(raw: u8) -> Self { + match raw { + 1 => Icmpv6Type::DestinationUnreachable, + 2 => Icmpv6Type::PacketTooBig, + 3 => Icmpv6Type::TimeExceeded, + 4 => Icmpv6Type::ParameterProblem, + 128 => Icmpv6Type::EchoRequest, + 129 => Icmpv6Type::EchoReply, + 130 => Icmpv6Type::MulticastListenerQuery, + 131 => Icmpv6Type::MulticastListenerReport, + 132 => Icmpv6Type::MulticastListenerDone, + 133 => Icmpv6Type::RouterSolicitation, + 134 => Icmpv6Type::RouterAdvertisement, + 135 => Icmpv6Type::NeighborSolicitation, + 136 => Icmpv6Type::NeighborAdvertisement, + 137 => Icmpv6Type::RedirectMessage, + 138 => Icmpv6Type::RouterRenumbering, + 139 => Icmpv6Type::NodeInformationQuery, + 140 => Icmpv6Type::NodeInformationResponse, + 141 => Icmpv6Type::InverseNeighborDiscoverySolicitation, + 142 => Icmpv6Type::InverseNeighborDiscoveryAdvertisement, + 143 => Icmpv6Type::Version2MulticastListenerReport, + 144 => Icmpv6Type::HomeAgentAddressDiscoveryRequest, + 145 => Icmpv6Type::HomeAgentAddressDiscoveryReply, + 146 => Icmpv6Type::MobilePrefixSolicitation, + 147 => Icmpv6Type::MobilePrefixAdvertisement, + 148 => Icmpv6Type::CertificationPathSolicitation, + 149 => Icmpv6Type::CertificationPathAdvertisement, + 151 => Icmpv6Type::MulticastRouterAdvertisement, + 152 => Icmpv6Type::MulticastRouterSolicitation, + 153 => Icmpv6Type::MulticastRouterTermination, + 154 => Icmpv6Type::Fmipv6Messages, + 155 => Icmpv6Type::RplControlMessage, + 156 => Icmpv6Type::Ilnpv6LocatorUpdateMessage, + 157 => Icmpv6Type::DuplicateAddressRequest, + 158 => Icmpv6Type::DuplicateAddressConfirmation, + 159 => Icmpv6Type::MplControlMessage, + 160 => Icmpv6Type::ExtendedEchoRequest, + 161 => Icmpv6Type::ExtendedEchoReply, + other => Icmpv6Type::Other(other), + } + } +} + +impl Decode for Icmpv6Header { + type Iterm = Icmpv6Header; + fn decode(input: &[u8]) -> IResult<&[u8], Icmpv6Header> { + let (input, icmp_type) = number::streaming::be_u8(input)?; + let (input, icmp_code) = number::streaming::be_u8(input)?; + let (input, checksum) = number::streaming::be_u16(input)?; + Ok(( + input, + Icmpv6Header { + icmp_type: Icmpv6Type::from(icmp_type), + icmp_code, + checksum, + }, + )) + } +} + +/****************************************************************************** + * TEST + ******************************************************************************/ + +#[cfg(test)] +mod tests { + use super::Icmpv6Header; + use super::Icmpv6Type; + use crate::protocol::codec::Decode; + const LAST_SLICE: &'static [u8] = &[ + 0x11, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 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, + ]; + + #[test] + fn icmpv6_header_decode() { + /* + * Internet Control Message Protocol v6 + * Type: Echo (ping) request (128) + * Code: 0 + * Checksum: 0x863c [correct] + * [Checksum Status: Good] + * Identifier: 0x110d + * Sequence: 0 + * [Response In: 2] + * Data (52 bytes) + * Data: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223… + * [Length: 52] + */ + let bytes = [ + 0x80, 0x00, 0x86, 0x3c, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 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, + ]; + + let expectation = Icmpv6Header { + icmp_type: Icmpv6Type::EchoRequest, + icmp_code: 0, + checksum: 0x863c, + }; + + assert_eq!(Icmpv6Header::decode(&bytes), Ok((LAST_SLICE, expectation))); + + // example + let result = Icmpv6Header::decode(&bytes); + if let Ok((payload, header)) = result { + 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 ba06b66..c82e203 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -8,4 +8,5 @@ pub mod tcp; pub mod dns; pub mod http; pub mod vlan; -pub mod icmp;
\ No newline at end of file +pub mod icmp; +pub mod icmpv6;
\ No newline at end of file diff --git a/src/protocol/vlan.rs b/src/protocol/vlan.rs index a6b7202..7f64780 100644 --- a/src/protocol/vlan.rs +++ b/src/protocol/vlan.rs @@ -83,8 +83,8 @@ mod tests { assert_eq!(VlanHeader::decode(&bytes), Ok((LAST_SLICE, expectation))); // example - let vlan = VlanHeader::decode(&bytes); - if let Ok((payload, header)) = vlan { + let result = VlanHeader::decode(&bytes); + if let Ok((payload, header)) = result { println!("return: {:?}, payload: {}", header, payload.len()); } else { println!("return: Incomplete data"); |
