use crate::protocol::ip::IPProtocol; use nom::bits; use nom::bytes; use nom::error::Error; use nom::number; use nom::sequence; use nom::IResult; use std::convert::TryFrom; use std::net::Ipv6Addr; /****************************************************************************** * Struct ******************************************************************************/ /* * IPv6 Header Format * * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |Version| Traffic Class | Flow Label | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Payload Length | Next Header | Hop Limit | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | * + + * | | * + Source Address + * | | * + + * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | | * + + * | | * + Destination Address + * | | * + + * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct IPv6Header { pub version: u8, // 4 bit pub dsc: u8, // Differentiated Services Codepoint: 6 bit pub ecn: u8, // Explicit Congestion Notification: 2 bit pub flow_label: u32, // 20 bit pub length: u16, pub next_header: IPProtocol, pub hop_limit: u8, pub source_address: Ipv6Addr, pub dest_address: Ipv6Addr, } /****************************************************************************** * API ******************************************************************************/ fn half_byte_decode(input: &[u8]) -> IResult<&[u8], (u8, u8)> { bits::bits::<_, _, Error<_>, _, _>(sequence::pair( bits::streaming::take(4u8), bits::streaming::take(4u8), ))(input) } fn address_v6_decode(input: &[u8]) -> IResult<&[u8], Ipv6Addr> { let (input, ipv6) = bytes::streaming::take(16u8)(input)?; Ok((input, Ipv6Addr::from(<[u8; 16]>::try_from(ipv6).unwrap()))) } impl IPv6Header { pub fn decode(input: &[u8]) -> IResult<&[u8], IPv6Header> { let (input, ver_tc) = half_byte_decode(input)?; let (input, tc_fl) = half_byte_decode(input)?; let (input, fl): (_, u32) = bits::bits::<_, _, Error<_>, _, _>(bits::streaming::take(16u8))(input)?; let (input, length) = number::streaming::be_u16(input)?; let (input, next_header) = IPProtocol::decode(input)?; let (input, hop_limit) = number::streaming::be_u8(input)?; let (input, source_address) = address_v6_decode(input)?; let (input, dest_address) = address_v6_decode(input)?; // TODO IPv6 Ext Header Decode Ok(( input, IPv6Header { version: ver_tc.0, dsc: (ver_tc.1 << 2) + ((tc_fl.0 & 0b1100) >> 2), ecn: tc_fl.0 & 0b11, flow_label: (u32::from(tc_fl.1) << 16) + fl, length, next_header, hop_limit, source_address, dest_address, }, )) } } /****************************************************************************** * TEST ******************************************************************************/ #[cfg(test)] mod tests { use super::IPv6Header; use crate::protocol::ip::IPProtocol; use std::net::Ipv6Addr; const LAST_SLICE: &'static [u8] = &[0xff]; #[test] fn ipv6_header_decode() { /* * Internet Protocol Version 6, Src: 2409:8034:4025::50:a31, Dst: 2409:8034:4040:5301::204 * 0110 .... = Version: 6 * .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT) * .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0) * .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0) * .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000 * Payload Length: 1416 * Next Header: UDP (17) * Hop Limit: 252 * Source Address: 2409:8034:4025::50:a31 * Destination Address: 2409:8034:4040:5301::204 */ let bytes = [ 0x60, /* Version and Partial Differentiated Services Codepoint */ 0x00, /* Partial Differentiated Services Codepoint and Explicit Congestion Notification and Partial Flow Label */ 0x00, 0x00, /* Partial Flow Label */ 0x05, 0x88, /* Payload Length */ 0x11, /* Next Header */ 0xfc, /* Hop Limit */ 0x24, 0x09, 0x80, 0x34, 0x40, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x0a, 0x31, /* Source Address */ 0x24, 0x09, 0x80, 0x34, 0x40, 0x40, 0x53, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, /* Destination Address */ 0xff, /* Payload */ ]; let expectation = IPv6Header { version: 6, dsc: 0, ecn: 0, flow_label: 0, length: 1416, next_header: IPProtocol::UDP, hop_limit: 252, source_address: Ipv6Addr::new( 0x2409, 0x8034, 0x4025, 0x0000, 0x0000, 0x0000, 0x0050, 0x0a31, ), dest_address: Ipv6Addr::new( 0x2409, 0x8034, 0x4040, 0x5301, 0x0000, 0x0000, 0x0000, 0x0204, ), }; assert_eq!(IPv6Header::decode(&bytes), Ok((LAST_SLICE, expectation))); // example let result = IPv6Header::decode(&bytes); if let Ok((payload, header)) = result { println!("return: {:?}, payload: {}", header, payload.len()); } else { println!("return: Incomplete data"); } } }