diff options
| -rw-r--r-- | src/event/event.rs | 12 | ||||
| -rw-r--r-- | src/main.rs | 59 | ||||
| -rw-r--r-- | src/packet/packet.rs | 89 | ||||
| -rw-r--r-- | src/plugin/example.rs | 7 | ||||
| -rw-r--r-- | src/protocol/ethernet.rs | 2 | ||||
| -rw-r--r-- | src/protocol/ip.rs | 29 | ||||
| -rw-r--r-- | src/protocol/ipv4.rs | 2 | ||||
| -rw-r--r-- | src/protocol/ipv6.rs | 342 | ||||
| -rw-r--r-- | src/protocol/mpls.rs | 4 | ||||
| -rw-r--r-- | src/protocol/tcp.rs | 2 | ||||
| -rw-r--r-- | src/protocol/udp.rs | 2 | ||||
| -rw-r--r-- | src/protocol/vlan.rs | 2 |
12 files changed, 439 insertions, 113 deletions
diff --git a/src/event/event.rs b/src/event/event.rs index e2e2842..8a4ddee 100644 --- a/src/event/event.rs +++ b/src/event/event.rs @@ -43,20 +43,20 @@ impl BuiltInEvent { mgr.borrow_mut().trigger(builtin_l3_event, session); } - pub fn trigger_ip4_event( + pub fn trigger_ipv4_event( mgr: Rc<RefCell<EventManager>>, session: Option<Rc<RefCell<Session>>>, ) { - let builtin_ip4_event = mgr.borrow_mut().event2index(BUILTIN_IPV4_EVENT); - mgr.borrow_mut().trigger(builtin_ip4_event, session); + let builtin_ipv4_event = mgr.borrow_mut().event2index(BUILTIN_IPV4_EVENT); + mgr.borrow_mut().trigger(builtin_ipv4_event, session); } - pub fn trigger_ip6_event( + pub fn trigger_ipv6_event( mgr: Rc<RefCell<EventManager>>, session: Option<Rc<RefCell<Session>>>, ) { - let builtin_ip6_event = mgr.borrow_mut().event2index(BUILTIN_IPV6_EVENT); - mgr.borrow_mut().trigger(builtin_ip6_event, session); + let builtin_ipv6_event = mgr.borrow_mut().event2index(BUILTIN_IPV6_EVENT); + mgr.borrow_mut().trigger(builtin_ipv6_event, session); } pub fn trigger_l4_event(mgr: Rc<RefCell<EventManager>>, session: Option<Rc<RefCell<Session>>>) { diff --git a/src/main.rs b/src/main.rs index cafd456..24e907c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,65 +4,60 @@ use stellar_rs::event::event::BuiltInEvent; use stellar_rs::event::manager::EventHandle; use stellar_rs::event::manager::EventManager; use stellar_rs::packet::capture::PacketCapture; +use stellar_rs::packet::packet::Encapsulation; use stellar_rs::packet::packet::Packet; -use stellar_rs::packet::packet::PacketEvent; use stellar_rs::plugin::example::ExamplePulgin; use stellar_rs::session::session::Session; use stellar_rs::session::session::SessionProto; use stellar_rs::session::session::SessionState; use stellar_rs::thread::thread::ThreadContex; -fn trigger_packet_event( +fn trigger_event_by_packet( packet: &Packet, session: Option<Rc<RefCell<Session>>>, event_mgr: Rc<RefCell<EventManager>>, ) { - for packet_event in &packet.event { - match packet_event { - PacketEvent::L2_EVENT => { - BuiltInEvent::trigger_l2_event(event_mgr.clone(), session.clone()); - } - PacketEvent::L2_ETH_EVENT => { + let num = packet.encapsulation.len(); + for i in 0..num { + match packet.encapsulation[i] { + Encapsulation::L2_ETH(_, _) => { // TODO } - PacketEvent::L2_VLAN_EVENT => { + Encapsulation::L2_VLAN(_, _) => { // TODO } - PacketEvent::L2_MPLS_EVENT => { + Encapsulation::L2_MPLS(_, _) => { // TODO } - PacketEvent::L2_PWETH_EVENT => { + Encapsulation::L2_PWETH(_, _) => { // TODO } - PacketEvent::L3_EVENT => { - BuiltInEvent::trigger_l3_event(event_mgr.clone(), session.clone()); - } - PacketEvent::L3_IPV4_EVENT => { - BuiltInEvent::trigger_ip4_event(event_mgr.clone(), session.clone()); - } - PacketEvent::L3_IPV6_EVENT => { - BuiltInEvent::trigger_ip6_event(event_mgr.clone(), session.clone()); + Encapsulation::L3_IPV4(_, _) => { + BuiltInEvent::trigger_ipv4_event(event_mgr.clone(), session.clone()); } - PacketEvent::L4_EVENT => { - BuiltInEvent::trigger_l4_event(event_mgr.clone(), session.clone()); + Encapsulation::L3_IPV6(_, _) => { + BuiltInEvent::trigger_ipv6_event(event_mgr.clone(), session.clone()); } - PacketEvent::L4_TCP_EVENT => { + Encapsulation::L4_TCP(_, _) => { BuiltInEvent::trigger_tcp_event(event_mgr.clone(), session.clone()); } - PacketEvent::L4_UDP_EVENT => { + Encapsulation::L4_UDP(_, _) => { BuiltInEvent::trigger_udp_event(event_mgr.clone(), session.clone()); } - PacketEvent::L4_ICMP_EVENT => { + Encapsulation::L4_ICMP(_, _) => { + // TODO + } + Encapsulation::L4_ICMPV6(_, _) => { // TODO } - PacketEvent::L4_ICMPV6_EVENT => { + Encapsulation::UNSUPPORTED(_) => { // TODO } } } } -fn trigger_session_event( +fn trigger_event_by_session( session: Option<Rc<RefCell<Session>>>, event_mgr: Rc<RefCell<EventManager>>, ) { @@ -93,7 +88,7 @@ fn trigger_session_event( } } -fn capture_callback(data: &[u8], len: u32, ctx: Rc<RefCell<ThreadContex>>) { +fn handle_one_packet(data: &[u8], len: u32, ctx: Rc<RefCell<ThreadContex>>) { let event_mgr = ctx.borrow_mut().get_event_mgr(); let session_mgr = ctx.borrow_mut().get_session_mgr(); @@ -119,11 +114,11 @@ fn capture_callback(data: &[u8], len: u32, ctx: Rc<RefCell<ThreadContex>>) { if packet.get_inner_tuple().is_some() { let flow_id = packet.get_flow_id().unwrap(); let session = session_mgr.borrow_mut().update(flow_id); - trigger_packet_event(&packet, Some(session.clone()), event_mgr.clone()); - trigger_session_event(Some(session.clone()), event_mgr.clone()); + trigger_event_by_packet(&packet, Some(session.clone()), event_mgr.clone()); + trigger_event_by_session(Some(session.clone()), event_mgr.clone()); // Packets have no sessions, only packet events are triggered } else { - trigger_packet_event(&packet, None, event_mgr.clone()); + trigger_event_by_packet(&packet, None, event_mgr.clone()); } // Handle packet events and session events on the current package @@ -131,7 +126,7 @@ fn capture_callback(data: &[u8], len: u32, ctx: Rc<RefCell<ThreadContex>>) { // Handle expire events without packets let session = session_mgr.borrow_mut().expire_oldest_session(); - trigger_session_event(session, event_mgr.clone()); + trigger_event_by_session(session, event_mgr.clone()); event_mgr.borrow_mut().dispatch(None); } @@ -142,5 +137,5 @@ fn main() { PacketCapture::show_devices(); let mut cap = PacketCapture::new("en0"); - cap.poll_packet(capture_callback, thread_ctx); + cap.poll_packet(handle_one_packet, thread_ctx); } diff --git a/src/packet/packet.rs b/src/packet/packet.rs index 82dd4f1..59dfce1 100644 --- a/src/packet/packet.rs +++ b/src/packet/packet.rs @@ -32,35 +32,11 @@ pub enum Encapsulation<'a> { UNSUPPORTED(&'a [u8]), } -#[allow(non_camel_case_types)] -#[derive(Clone, Debug, PartialEq)] -pub enum PacketEvent { - // L2 Layer Event - L2_EVENT, - L2_ETH_EVENT, - L2_VLAN_EVENT, - L2_MPLS_EVENT, - L2_PWETH_EVENT, - - // L3 Layer Event - L3_EVENT, - L3_IPV4_EVENT, - L3_IPV6_EVENT, - - // L4 Layer Event - L4_EVENT, - L4_TCP_EVENT, - L4_UDP_EVENT, - L4_ICMP_EVENT, - L4_ICMPV6_EVENT, -} - #[derive(Debug)] pub struct Packet<'a> { pub orig_data: &'a [u8], pub orig_len: u32, pub encapsulation: Vec<Encapsulation<'a>>, - pub event: Vec<PacketEvent>, } impl Packet<'_> { @@ -69,7 +45,6 @@ impl Packet<'_> { orig_data: data, orig_len: len, encapsulation: vec![], - event: vec![], } } @@ -376,14 +351,12 @@ fn handle_eth<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packet if let Ok((payload, header)) = result { dbg!(&header); + let next_proto = header.ether_type; packet .encapsulation .push(Encapsulation::L2_ETH(header, payload)); - packet.event.push(PacketEvent::L2_EVENT); - packet.event.push(PacketEvent::L2_ETH_EVENT); - - return handle_l3(packet, payload, header.ether_type); + return handle_l3(packet, payload, next_proto); } else { return Err(PacketError::IncompleteEthernetFrame); } @@ -394,14 +367,12 @@ fn handle_vlan<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packe if let Ok((payload, header)) = result { dbg!(&header); + let next_proto = header.ether_type; packet .encapsulation .push(Encapsulation::L2_VLAN(header, payload)); - packet.event.push(PacketEvent::L2_EVENT); - packet.event.push(PacketEvent::L2_VLAN_EVENT); - - return handle_l3(packet, payload, header.ether_type); + return handle_l3(packet, payload, next_proto); } else { return Err(PacketError::IncompleteVlanHeader); } @@ -412,14 +383,12 @@ fn handle_mpls<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packe if let Ok((payload, header)) = result { dbg!(&header); + let bottom_of_stack = header.bottom_of_stack; packet .encapsulation .push(Encapsulation::L2_MPLS(header, payload)); - packet.event.push(PacketEvent::L2_EVENT); - packet.event.push(PacketEvent::L2_MPLS_EVENT); - - if header.bottom_of_stack { + if bottom_of_stack { if payload.len() < 1 { return Ok(()); } @@ -448,9 +417,6 @@ fn handle_pw_eth<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Pac .encapsulation .push(Encapsulation::L2_PWETH(header, payload)); - packet.event.push(PacketEvent::L2_EVENT); - packet.event.push(PacketEvent::L2_PWETH_EVENT); - return handle_eth(packet, payload); } else { return Err(PacketError::IncompletePwEthHeader); @@ -462,16 +428,14 @@ fn handle_ipv4<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packe if let Ok((payload, header)) = result { dbg!(&header); + let next_proto = header.protocol; packet .encapsulation .push(Encapsulation::L3_IPV4(header, payload)); // TODO IPv4 Fragment - packet.event.push(PacketEvent::L3_EVENT); - packet.event.push(PacketEvent::L3_IPV4_EVENT); - - return handle_l4(packet, payload, header.protocol); + return handle_l4(packet, payload, next_proto); } else { return Err(PacketError::IncompleteIpv4Header); } @@ -482,16 +446,20 @@ fn handle_ipv6<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packe if let Ok((payload, header)) = result { dbg!(&header); + let mut next_proto = header.next_header; + for extension in header.extensions.iter() { + next_proto = extension.next_header; + + if next_proto == IPProtocol::IPV6_FRAGMENT_HDR { + // TODO IPv6 Fragment + } + } + packet .encapsulation .push(Encapsulation::L3_IPV6(header, payload)); - // TODO IPv6 Fragment - - packet.event.push(PacketEvent::L3_EVENT); - packet.event.push(PacketEvent::L3_IPV6_EVENT); - - return handle_l4(packet, payload, header.next_header); + return handle_l4(packet, payload, next_proto); } else { return Err(PacketError::IncompleteIpv6Header); } @@ -508,9 +476,6 @@ fn handle_tcp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packet // TODO TCP Reassembly - packet.event.push(PacketEvent::L4_EVENT); - packet.event.push(PacketEvent::L4_TCP_EVENT); - return Ok(()); } else { return Err(PacketError::IncompleteTcpHeader); @@ -526,9 +491,6 @@ fn handle_udp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packet .encapsulation .push(Encapsulation::L4_UDP(header, payload)); - packet.event.push(PacketEvent::L4_EVENT); - packet.event.push(PacketEvent::L4_UDP_EVENT); - return Ok(()); } else { return Err(PacketError::IncompleteUdpHeader); @@ -544,9 +506,6 @@ fn handle_icmp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packe .encapsulation .push(Encapsulation::L4_ICMP(header, payload)); - packet.event.push(PacketEvent::L4_EVENT); - packet.event.push(PacketEvent::L4_ICMP_EVENT); - return Ok(()); } else { return Err(PacketError::IncompleteIcmpHeader); @@ -562,9 +521,6 @@ fn handle_icmpv6<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Pac .encapsulation .push(Encapsulation::L4_ICMPV6(header, payload)); - packet.event.push(PacketEvent::L4_EVENT); - packet.event.push(PacketEvent::L4_ICMPV6_EVENT); - return Ok(()); } else { return Err(PacketError::IncompleteIcmpv6Header); @@ -662,6 +618,7 @@ mod tests { dest_address: Ipv6Addr::new( 0x2409, 0x8034, 0x4040, 0x5301, 0x0000, 0x0000, 0x0000, 0x0204, ), + extensions: Vec::new(), }; let tcp_hdr = TcpHeader { source_port: 50081, @@ -929,7 +886,6 @@ mod tests { &bytes[42..] ) ); - assert_eq!( packet.encapsulation[4], Encapsulation::L4_TCP( @@ -954,6 +910,7 @@ mod tests { &bytes[62..] ) ); + // assert_eq!(1, 0); } @@ -1152,6 +1109,8 @@ mod tests { &bytes[62..] ) ) + + // assert_eq!(1, 0); } #[test] @@ -1348,6 +1307,7 @@ mod tests { hop_limit: 64, source_address: Ipv6Addr::new(0x2001, 0x0, 0x0, 0x0, 0x192, 0x168, 0x40, 0x134), dest_address: Ipv6Addr::new(0x2001, 0x0, 0x0, 0x0, 0x192, 0x168, 0x40, 0x133), + extensions: Vec::new(), }, &bytes[54..] ) @@ -1574,6 +1534,7 @@ mod tests { dest_address: Ipv6Addr::new( 0x2600, 0x140e, 0x0006, 0x0000, 0x0000, 0x0000, 0x1702, 0x1058 ), + extensions: Vec::new(), }, &bytes[74..] ) @@ -1720,6 +1681,7 @@ mod tests { dest_address: Ipv6Addr::new( 0x2001, 0x04f8, 0x0004, 0x0007, 0x02e0, 0x81ff, 0xfe52, 0x9a6b ), + extensions: Vec::new(), }, &bytes[54..] ) @@ -1741,6 +1703,7 @@ mod tests { dest_address: Ipv6Addr::new( 0xcafe, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xbabe ), + extensions: Vec::new(), }, &bytes[94..] ) diff --git a/src/plugin/example.rs b/src/plugin/example.rs index a3ca852..6819d75 100644 --- a/src/plugin/example.rs +++ b/src/plugin/example.rs @@ -82,6 +82,13 @@ impl EventHandle for ExamplePulgin { return; } + let length = packet.unwrap().orig_len; + let flow_id = packet.unwrap().get_flow_id(); + println!( + "{} handle Packet: {:?} {:?}", + self.plugin_name, length, flow_id + ); + self.plugin_ctx.borrow_mut().clear(); self.plugin_ctx.borrow_mut().push_str("1"); diff --git a/src/protocol/ethernet.rs b/src/protocol/ethernet.rs index 6e25696..a588c0d 100644 --- a/src/protocol/ethernet.rs +++ b/src/protocol/ethernet.rs @@ -60,7 +60,7 @@ pub enum EtherType { Other(u16), } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct EthernetFrame { pub source_mac: MacAddress, pub dest_mac: MacAddress, diff --git a/src/protocol/ip.rs b/src/protocol/ip.rs index d7a1fe9..8d22e15 100644 --- a/src/protocol/ip.rs +++ b/src/protocol/ip.rs @@ -6,9 +6,10 @@ use nom::IResult; * Struct ******************************************************************************/ +#[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum IPProtocol { - HOPOPT, + IPV6_HOP_HDR, ICMP, IGMP, GGP, @@ -27,7 +28,12 @@ pub enum IPProtocol { CHAOS, UDP, IPV6, + IPV6_ROUTING_HDR, + IPV6_FRAGMENT_HDR, + ESP, + AUTH, ICMP6, + IPV6_DEST_HDR, Other(u8), } @@ -38,7 +44,7 @@ pub enum IPProtocol { impl From<u8> for IPProtocol { fn from(raw: u8) -> Self { match raw { - 0 => IPProtocol::HOPOPT, + 0 => IPProtocol::IPV6_HOP_HDR, // IPv6 Hop-by-Hop Options 1 => IPProtocol::ICMP, 2 => IPProtocol::IGMP, 3 => IPProtocol::GGP, @@ -57,12 +63,31 @@ impl From<u8> for IPProtocol { 16 => IPProtocol::CHAOS, 17 => IPProtocol::UDP, 41 => IPProtocol::IPV6, + 43 => IPProtocol::IPV6_ROUTING_HDR, // IPv6 Routing Header + 44 => IPProtocol::IPV6_FRAGMENT_HDR, // IPv6 Fragment Header + 50 => IPProtocol::ESP, // Encap Security Payload [RFC4303] + 51 => IPProtocol::AUTH, // Authentication Header [RFC4302] 58 => IPProtocol::ICMP6, + 60 => IPProtocol::IPV6_DEST_HDR, // IPv6 Destination Options other => IPProtocol::Other(other), } } } +impl IPProtocol { + pub fn is_ipv6_ext_header(next_header: IPProtocol) -> bool { + match next_header { + IPProtocol::IPV6_HOP_HDR => true, + IPProtocol::IPV6_ROUTING_HDR => true, + IPProtocol::IPV6_FRAGMENT_HDR => true, + // IPProtocol::ESP => true, + IPProtocol::AUTH => true, + IPProtocol::IPV6_DEST_HDR => true, + _ => false, + } + } +} + impl Decode for IPProtocol { type Iterm = IPProtocol; fn decode(input: &[u8]) -> IResult<&[u8], IPProtocol> { diff --git a/src/protocol/ipv4.rs b/src/protocol/ipv4.rs index f0ee008..61dce29 100644 --- a/src/protocol/ipv4.rs +++ b/src/protocol/ipv4.rs @@ -31,7 +31,7 @@ use std::net::Ipv4Addr; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct IPv4Header { pub version: u8, // 4 bit pub ihl: u8, // 4 bit diff --git a/src/protocol/ipv6.rs b/src/protocol/ipv6.rs index f8bafdd..5a30847 100644 --- a/src/protocol/ipv6.rs +++ b/src/protocol/ipv6.rs @@ -41,7 +41,32 @@ use std::net::Ipv6Addr; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +/* + * IPv6 AH 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Next Header | Payload Len | RESERVED | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Security Parameters Index (SPI) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Sequence Number Field | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + Integrity Check Value-ICV (variable) | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct IPv6Extension { + pub next_header: IPProtocol, + pub ext_length: u8, // Extension total Length + pub data: Vec<u8>, // Extension data length (ext_length - 2) +} + +#[derive(Clone, Debug, PartialEq, Eq)] pub struct IPv6Header { pub version: u8, // 4 bit pub dsc: u8, // Differentiated Services Codepoint: 6 bit @@ -52,6 +77,7 @@ pub struct IPv6Header { pub hop_limit: u8, pub source_address: Ipv6Addr, pub dest_address: Ipv6Addr, + pub extensions: Vec<IPv6Extension>, } /****************************************************************************** @@ -71,6 +97,34 @@ fn address_v6_decode(input: &[u8]) -> IResult<&[u8], Ipv6Addr> { Ok((input, Ipv6Addr::from(<[u8; 16]>::try_from(ipv6).unwrap()))) } +fn extension_decode(input: &[u8], curr_proto: IPProtocol) -> IResult<&[u8], IPv6Extension> { + let (input, next_header) = IPProtocol::decode(input)?; + let (input, mut ext_length) = number::streaming::be_u8(input)?; + + /* + * https://datatracker.ietf.org/doc/html/rfc4302#page-4 + * + * (Note that although IPv6 [DH98] characterizes AH as + * an extension header, its length is measured in 32-bit words, not the + * 64-bit words used by other IPv6 extension headers.) + */ + if curr_proto == IPProtocol::AUTH { + ext_length = ext_length * 4 + 8 // update Authentication Header length + } else { + ext_length = ext_length * 8 + 8; // update other extension header length + } + let (input, data) = bytes::streaming::take(ext_length - 2)(input)?; + + Ok(( + input, + IPv6Extension { + next_header, + ext_length, + data: data.to_vec(), + }, + )) +} + impl Decode for IPv6Header { type Iterm = IPv6Header; fn decode(input: &[u8]) -> IResult<&[u8], IPv6Header> { @@ -84,10 +138,18 @@ impl Decode for IPv6Header { let (input, source_address) = address_v6_decode(input)?; let (input, dest_address) = address_v6_decode(input)?; - // TODO IPv6 Ext Header Decode + let mut remain = input; + let mut next_proto = next_header; + let mut extensions = Vec::new(); + while IPProtocol::is_ipv6_ext_header(next_proto) { + let (left, extension) = extension_decode(remain, next_proto)?; + remain = left; + next_proto = extension.next_header; + extensions.push(extension); + } Ok(( - input, + remain, IPv6Header { version: ver_tc.0, dsc: (ver_tc.1 << 2) + ((tc_fl.0 & 0b1100) >> 2), @@ -98,6 +160,7 @@ impl Decode for IPv6Header { hop_limit, source_address, dest_address, + extensions, }, )) } @@ -109,6 +172,7 @@ impl Decode for IPv6Header { #[cfg(test)] mod tests { + use super::IPv6Extension; use super::IPv6Header; use crate::protocol::codec::Decode; use crate::protocol::ip::IPProtocol; @@ -160,6 +224,81 @@ mod tests { dest_address: Ipv6Addr::new( 0x2409, 0x8034, 0x4040, 0x5301, 0x0000, 0x0000, 0x0000, 0x0204, ), + extensions: Vec::new(), + }; + + 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"); + } + } + + #[test] + fn ipv6_hop_extension_decode() { + /* + * Internet Protocol Version 6, Src: ::, Dst: ff02::16 + * 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: 36 + * Next Header: IPv6 Hop-by-Hop Option (0) + * Hop Limit: 1 + * Source Address: :: + * Destination Address: ff02::16 + * IPv6 Hop-by-Hop Option + * Next Header: ICMPv6 (58) + * Length: 0 + * [Length: 8 bytes] + * Router Alert + * Type: Router Alert (0x05) + * 00.. .... = Action: Skip and continue (0) + * ..0. .... = May Change: No + * ...0 0101 = Low-Order Bits: 0x05 + * Length: 2 + * Router Alert: MLD (0) + * PadN + * Type: PadN (0x01) + * 00.. .... = Action: Skip and continue (0) + * ..0. .... = May Change: No + * ...0 0001 = Low-Order Bits: 0x01 + * Length: 0 + * PadN: <none> + */ + + let bytes = [ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x3a, 0x00, + 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, /* Extensions Data */ + 0xff, /* Payload */ + ]; + + let expectation = IPv6Header { + version: 6, + dsc: 0, + ecn: 0, + flow_label: 0, + length: 36, + next_header: IPProtocol::IPV6_HOP_HDR, + hop_limit: 1, + source_address: Ipv6Addr::new( + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + ), + dest_address: Ipv6Addr::new( + 0xff02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0016, + ), + extensions: vec![IPv6Extension { + next_header: IPProtocol::ICMP6, + ext_length: 8, + data: vec![0x05, 0x02, 0x00, 0x00, 0x01, 0x00], + }], }; assert_eq!(IPv6Header::decode(&bytes), Ok((LAST_SLICE, expectation))); @@ -171,5 +310,202 @@ mod tests { } else { println!("return: Incomplete data"); } + + // assert_eq!(1, 0); + } + + #[test] + fn ipv6_routing_extension_decode() { + /* + * Internet Protocol Version 6, Src: 2200::244:212:3fff:feae:22f7, Dst: 2200::240:2:0:0:4 + * 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: 32 + * Next Header: Routing Header for IPv6 (43) + * Hop Limit: 4 + * Source Address: 2200::244:212:3fff:feae:22f7 + * Destination Address: 2200::240:2:0:0:4 + * [Source SLAAC MAC: Dell_ae:22:f7 (00:12:3f:ae:22:f7)] + * Routing Header for IPv6 (Segment Routing) + * Next Header: ICMPv6 (58) + * Length: 2 + * [Length: 24 bytes] + * Type: Segment Routing (4) + * Segments Left: 1 + * Last Entry: 0 + * Flags: 0x00 + * Tag: 0000 + * Address[0]: 2200::210:2:0:0:4 + */ + + let bytes = [ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x2b, 0x04, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x44, 0x02, 0x12, 0x3f, 0xff, 0xfe, 0xae, 0x22, 0xf7, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3a, 0x02, + 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* Extensions Data */ + 0xff, /* Payload */ + ]; + + let expectation = IPv6Header { + version: 6, + dsc: 0, + ecn: 0, + flow_label: 0, + length: 32, + next_header: IPProtocol::IPV6_ROUTING_HDR, + hop_limit: 4, + source_address: Ipv6Addr::new( + 0x2200, 0x0000, 0x0000, 0x0244, 0x0212, 0x3fff, 0xfeae, 0x22f7, + ), + dest_address: Ipv6Addr::new( + 0x2200, 0x0000, 0x0000, 0x0240, 0x0002, 0x0000, 0x0000, 0x0004, + ), + extensions: vec![IPv6Extension { + next_header: IPProtocol::ICMP6, + ext_length: 24, + data: vec![ + 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + ], + }], + }; + + 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"); + } + + // assert_eq!(1, 0); + } + + #[test] + fn ipv6_auth_extension_decode() { + // TODO need test + } + + #[test] + fn ipv6_mutil_extension_decode() { + /* + * Internet Protocol Version 6, Src: ::1, Dst: ::3 + * 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: 32 + * Next Header: IPv6 Hop-by-Hop Option (0) + * Hop Limit: 64 + * Source Address: ::1 + * Destination Address: ::3 + * IPv6 Hop-by-Hop Option + * Next Header: Destination Options for IPv6 (60) + * Length: 0 + * [Length: 8 bytes] + * PadN + * Type: PadN (0x01) + * 00.. .... = Action: Skip and continue (0) + * ..0. .... = May Change: No + * ...0 0001 = Low-Order Bits: 0x01 + * Length: 4 + * PadN: 00000000 + * Destination Options for IPv6 + * Next Header: Routing Header for IPv6 (43) + * Length: 0 + * [Length: 8 bytes] + * PadN + * Type: PadN (0x01) + * 00.. .... = Action: Skip and continue (0) + * ..0. .... = May Change: No + * ...0 0001 = Low-Order Bits: 0x01 + * Length: 4 + * PadN: 00000000 + * Routing Header for IPv6 (Source Route) + * Next Header: Fragment Header for IPv6 (44) + * Length: 0 + * [Length: 8 bytes] + * Type: Source Route (0) + * [Expert Info (Note/Deprecated): Routing header type is deprecated] + * [Routing header type is deprecated] + * [Severity level: Note] + * [Group: Deprecated] + * Segments Left: 0 + * Reserved: 00000000 + * Fragment Header for IPv6 + * Next header: No Next Header for IPv6 (59) + * Reserved octet: 0x00 + * 0000 0000 0000 0... = Offset: 0 (0 bytes) + * .... .... .... .00. = Reserved bits: 0 + * .... .... .... ...0 = More Fragments: No + * Identification: 0x00000000 + */ + + let bytes = [ + 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x00, + 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, /* Extensions Data */ + 0xff, /* Payload */ + ]; + + let expectation = IPv6Header { + version: 6, + dsc: 0, + ecn: 0, + flow_label: 0, + length: 32, + next_header: IPProtocol::IPV6_HOP_HDR, + hop_limit: 64, + source_address: Ipv6Addr::new( + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, + ), + dest_address: Ipv6Addr::new( + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, + ), + extensions: vec![ + IPv6Extension { + next_header: IPProtocol::IPV6_DEST_HDR, + ext_length: 8, + data: vec![0x01, 0x04, 0x00, 0x00, 0x00, 0x00], + }, + IPv6Extension { + next_header: IPProtocol::IPV6_ROUTING_HDR, + ext_length: 8, + data: vec![0x01, 0x04, 0x00, 0x00, 0x00, 0x00], + }, + IPv6Extension { + next_header: IPProtocol::IPV6_FRAGMENT_HDR, + ext_length: 8, + data: vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + }, + IPv6Extension { + next_header: IPProtocol::Other(59), + ext_length: 8, + data: vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + }, + ], + }; + + 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"); + } + + // assert_eq!(1, 0); } } diff --git a/src/protocol/mpls.rs b/src/protocol/mpls.rs index 2c4c443..e6a7a37 100644 --- a/src/protocol/mpls.rs +++ b/src/protocol/mpls.rs @@ -9,7 +9,7 @@ use nom::IResult; * Struct ******************************************************************************/ -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct MplsHeader { pub label: u32, pub experimental: u8, @@ -17,7 +17,7 @@ pub struct MplsHeader { pub ttl: u8, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] // Ethernet pseudowire (PW) https://tools.ietf.org/html/rfc4448#section-3.1 pub struct PwEthHeader { pub control_word: u32, diff --git a/src/protocol/tcp.rs b/src/protocol/tcp.rs index a34fc37..5a88b25 100644 --- a/src/protocol/tcp.rs +++ b/src/protocol/tcp.rs @@ -69,7 +69,7 @@ pub enum TcpOption { }, } -#[derive(Clone, Debug, PartialEq, Eq, Default)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct TcpHeader { pub source_port: u16, pub dest_port: u16, diff --git a/src/protocol/udp.rs b/src/protocol/udp.rs index 0eba88f..43cf75c 100644 --- a/src/protocol/udp.rs +++ b/src/protocol/udp.rs @@ -20,7 +20,7 @@ use nom::IResult; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct UdpHeader { pub source_port: u16, pub dest_port: u16, diff --git a/src/protocol/vlan.rs b/src/protocol/vlan.rs index 7f64780..7533e41 100644 --- a/src/protocol/vlan.rs +++ b/src/protocol/vlan.rs @@ -9,7 +9,7 @@ use nom::IResult; * Struct ******************************************************************************/ -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct VlanHeader { // A 3 bit number which refers to the IEEE 802.1p class of service and maps to the frame priority level. pub priority_code_point: u8, |
