use crate::protocol::codec::Decode; use nom::number; use nom::IResult; /****************************************************************************** * Struct ******************************************************************************/ #[derive(Debug, PartialEq)] 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(Debug, PartialEq)] pub struct ICMPv6Header { pub icmp_type: ICMPv6Type, pub icmp_code: u8, pub checksum: u16, } /****************************************************************************** * API ******************************************************************************/ impl From 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); match result { Ok((payload, header)) => { println!("OK: {:?}, payload: {}", header, payload.len()); } Err(e) => { println!("ERR: {:?}", e); } } // assert_eq!(1, 0); } }