summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/event/event.rs12
-rw-r--r--src/main.rs59
-rw-r--r--src/packet/packet.rs89
-rw-r--r--src/plugin/example.rs7
-rw-r--r--src/protocol/ethernet.rs2
-rw-r--r--src/protocol/ip.rs29
-rw-r--r--src/protocol/ipv4.rs2
-rw-r--r--src/protocol/ipv6.rs342
-rw-r--r--src/protocol/mpls.rs4
-rw-r--r--src/protocol/tcp.rs2
-rw-r--r--src/protocol/udp.rs2
-rw-r--r--src/protocol/vlan.rs2
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,