use crate::protocol::codec::Decode; use crate::protocol::ethernet::EtherType; use nom::bits; use nom::bytes; use nom::error::Error; use nom::number; use nom::sequence; use nom::IResult; /****************************************************************************** * Struct ******************************************************************************/ /* * GRE Header Format (Version 0) * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |C|R|K|S|s|Recur| Flags | Ver | Protocol Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Checksum (optional) | Offset (optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Key (optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sequence Number (optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Routing (optional) * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Address Family | SRE Offset | SRE Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Routing Information ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * https://datatracker.ietf.org/doc/html/rfc1701 * https://datatracker.ietf.org/doc/html/rfc2890 */ #[derive(Clone, Debug, PartialEq, Eq)] pub struct SourceRouteEntry { pub address_family: u16, pub sre_offset: u8, pub sre_length: u8, pub sre_routing: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct Grev0Header { pub flag_checksum: bool, pub flag_routing: bool, pub flag_key: bool, pub flag_sequence: bool, pub flag_strictroute: bool, pub recursion_control: u8, pub flags: u8, pub version: u8, pub protocol_type: EtherType, pub checksum: Option, pub offset: Option, pub key: Option, pub sequence_number: Option, pub routing: Option>, } /****************************************************************************** * API ******************************************************************************/ fn source_route_entry_decode(input: &[u8]) -> IResult<&[u8], SourceRouteEntry> { let (input, address_family) = number::streaming::be_u16(input)?; let (input, sre_offset) = number::streaming::be_u8(input)?; let (input, sre_length) = number::streaming::be_u8(input)?; /* * The routing field is terminated with a "NULL" SRE containing an * address family of type 0x0000 and a length of 0. */ let (input, sre_routing) = match (address_family, sre_length) { (_, 0) => (input, vec![]), (_, _) => bytes::streaming::take(sre_length)(input).map(|(i, l)| (i, l.to_vec()))?, }; Ok(( input, SourceRouteEntry { address_family, sre_offset, sre_length, sre_routing, }, )) } impl Decode for Grev0Header { type Iterm = Grev0Header; fn decode(input: &[u8]) -> IResult<&[u8], Grev0Header> { let ( input, ( flag_checksum, flag_routing, flag_key, flag_sequence, flag_strictroute, recursion_control, flags, version, ), ): (&[u8], (u8, u8, u8, u8, u8, u8, u8, u8)) = bits::bits::<_, _, Error<_>, _, _>(sequence::tuple(( bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(3u8), bits::streaming::take(5u8), bits::streaming::take(3u8), )))(input)?; if version != 0 { return Err(nom::Err::Error(Error::new( input, nom::error::ErrorKind::Verify, ))); } let (input, protocol_type) = EtherType::decode(input)?; let (input, checksum) = match (flag_checksum, flag_routing) { (0, 0) => (input, None), (_, _) => number::streaming::be_u16(input).map(|(i, l)| (i, Some(l)))?, }; let (input, offset) = match (flag_checksum, flag_routing) { (0, 0) => (input, None), (_, _) => number::streaming::be_u16(input).map(|(i, l)| (i, Some(l)))?, }; let (input, key) = match flag_key { 0 => (input, None), _ => number::streaming::be_u32(input).map(|(i, l)| (i, Some(l)))?, }; let (input, sequence_number) = match flag_sequence { 0 => (input, None), _ => number::streaming::be_u32(input).map(|(i, l)| (i, Some(l)))?, }; let (input, routing) = match flag_routing { 0 => (input, None), _ => { let mut left = input; let mut routing = Vec::new(); loop { let (i, sre) = source_route_entry_decode(left)?; let length = sre.sre_length; routing.push(sre); left = i; if length == 0 { break; } } (left, Some(routing)) } }; Ok(( input, Grev0Header { flag_checksum: flag_checksum == 1, flag_routing: flag_routing == 1, flag_key: flag_key == 1, flag_sequence: flag_sequence == 1, flag_strictroute: flag_strictroute == 1, recursion_control, flags, version, protocol_type, checksum, offset, key, sequence_number, routing, }, )) } } /****************************************************************************** * TEST ******************************************************************************/ #[cfg(test)] mod tests { use super::Grev0Header; use super::SourceRouteEntry; use crate::protocol::codec::Decode; use crate::protocol::ethernet::EtherType; const LAST_SLICE: &'static [u8] = &[0xff]; #[test] // Enable Key Bit fn grev0_header_decode1() { /* * Generic Routing Encapsulation (IP) * Flags and Version: 0x2000 * 0... .... .... .... = Checksum Bit: No * .0.. .... .... .... = Routing Bit: No * ..1. .... .... .... = Key Bit: Yes * ...0 .... .... .... = Sequence Number Bit: No * .... 0... .... .... = Strict Source Route Bit: No * .... .000 .... .... = Recursion control: 0 * .... .... 0000 0... = Flags (Reserved): 0 * .... .... .... .000 = Version: GRE (0) * Protocol Type: IP (0x0800) * Key: 0x00000384 */ let bytes = [ 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x84, 0xff, /* Payload */ ]; let expectation = Grev0Header { flag_checksum: false, flag_routing: false, flag_key: true, flag_sequence: false, flag_strictroute: false, recursion_control: 0, flags: 0, version: 0, protocol_type: EtherType::IPv4, checksum: None, offset: None, key: Some(0x384), sequence_number: None, routing: None, }; assert_eq!(Grev0Header::decode(&bytes), Ok((LAST_SLICE, expectation))); // example let result = Grev0Header::decode(&bytes); if let Ok((payload, header)) = result { println!("return: {:?}, payload: {}", header, payload.len()); } else { println!("return: Incomplete data"); } } #[test] // Enable Routing Bit fn grev0_header_decode2() { /* * Generic Routing Encapsulation (IP) * Flags and Version: 0xc000 * 1... .... .... .... = Checksum Bit: Yes * .1.. .... .... .... = Routing Bit: Yes * ..0. .... .... .... = Key Bit: No * ...0 .... .... .... = Sequence Number Bit: No * .... 0... .... .... = Strict Source Route Bit: No * .... .000 .... .... = Recursion control: 0 * .... .... 0000 0... = Flags (Reserved): 0 * .... .... .... .000 = Version: GRE (0) * Protocol Type: IP (0x0800) * Checksum: 0x0000 incorrect, should be 0xea95 * [Expert Info (Warning/Protocol): Incorrect GRE Checksum [should be 0xea95]] * [Incorrect GRE Checksum [should be 0xea95]] * [Severity level: Warning] * [Group: Protocol] * [Checksum Status: Bad] * Offset: 44 * Routing * Address Family: 2 * SRE Offset: 0 * SRE Length: 44 * Routing Information: 6c696e6b5f696e666f206c696e6b5f696e666f206c696e6b5f696e666f206c696e6b5f69… * Routing * Address Family: 0 * SRE Offset: 0 * SRE Length: 0 */ let bytes = [ 0xc0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x2c, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* Payload */ ]; let expectation = Grev0Header { flag_checksum: true, flag_routing: true, flag_key: false, flag_sequence: false, flag_strictroute: false, recursion_control: 0, flags: 0, version: 0, protocol_type: EtherType::IPv4, checksum: Some(0x0000), offset: Some(44), key: None, sequence_number: None, routing: Some(vec![ SourceRouteEntry { address_family: 2, sre_offset: 0, sre_length: 44, sre_routing: vec![ 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x00, 0x00, 0x00, 0x00, ], }, SourceRouteEntry { address_family: 0, sre_offset: 0, sre_length: 0, sre_routing: vec![], }, ]), }; assert_eq!(Grev0Header::decode(&bytes), Ok((LAST_SLICE, expectation))); // example let result = Grev0Header::decode(&bytes); if let Ok((payload, header)) = result { println!("return: {:?}, payload: {}", header, payload.len()); } else { println!("return: Incomplete data"); } } }