summaryrefslogtreecommitdiff
path: root/src/protocol
diff options
context:
space:
mode:
authorluwenpeng <[email protected]>2023-07-28 12:14:01 +0800
committerluwenpeng <[email protected]>2023-08-01 11:44:26 +0800
commit9dd56a85f858f73fbc03079349f4c4b9b3295b79 (patch)
treeadb7df5c41767de9162a622a2480fb7409c9eb04 /src/protocol
parentd9d9bd0e6343e319c93585fea4a6844e7b91088c (diff)
[feature] Support IPv6 Decode
Diffstat (limited to 'src/protocol')
-rw-r--r--src/protocol/ipv6.rs170
-rw-r--r--src/protocol/mod.rs3
2 files changed, 172 insertions, 1 deletions
diff --git a/src/protocol/ipv6.rs b/src/protocol/ipv6.rs
new file mode 100644
index 0000000..283172b
--- /dev/null
+++ b/src/protocol/ipv6.rs
@@ -0,0 +1,170 @@
+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)?;
+
+ 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");
+ }
+ }
+}
diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs
index 2fd8d7d..7a3bb05 100644
--- a/src/protocol/mod.rs
+++ b/src/protocol/mod.rs
@@ -1,3 +1,4 @@
pub mod ethernet;
pub mod ip;
-pub mod ipv4; \ No newline at end of file
+pub mod ipv4;
+pub mod ipv6; \ No newline at end of file