summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluwenpeng <[email protected]>2023-09-08 19:50:57 +0800
committerluwenpeng <[email protected]>2023-09-08 19:50:57 +0800
commit3f92925d9c2f7c9417dea89470d9376d09b717f5 (patch)
tree7274476e1265c15f7bd9e83de902795458445b06
parent3c6fc844b5e15ae85e08f8bee18e54c30f33d988 (diff)
[feature] Support MPLS/PW Decode
-rw-r--r--src/main.rs20
-rw-r--r--src/packet/error.rs4
-rw-r--r--src/packet/packet.rs493
-rw-r--r--src/protocol/mod.rs3
-rw-r--r--src/protocol/mpls.rs123
5 files changed, 613 insertions, 30 deletions
diff --git a/src/main.rs b/src/main.rs
index 8ffdb9c..142fa83 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -22,31 +22,37 @@ fn trigger_packet_event(
PacketEvent::L2_EVENT => {
BuiltInEvent::trigger_l2_event(event_mgr.clone(), session.clone());
}
- PacketEvent::L2_VLAN => {
+ PacketEvent::L2_VLAN_EVENT => {
+ // TODO
+ }
+ PacketEvent::L2_MPLS_EVENT => {
+ // TODO
+ }
+ PacketEvent::L2_PWETH_EVENT => {
// TODO
}
PacketEvent::L3_EVENT => {
BuiltInEvent::trigger_l3_event(event_mgr.clone(), session.clone());
}
- PacketEvent::IPV4_EVENT => {
+ PacketEvent::L3_IPV4_EVENT => {
BuiltInEvent::trigger_ip4_event(event_mgr.clone(), session.clone());
}
- PacketEvent::IPV6_EVENT => {
+ PacketEvent::L3_IPV6_EVENT => {
BuiltInEvent::trigger_ip6_event(event_mgr.clone(), session.clone());
}
PacketEvent::L4_EVENT => {
BuiltInEvent::trigger_l4_event(event_mgr.clone(), session.clone());
}
- PacketEvent::TCP_EVENT => {
+ PacketEvent::L4_TCP_EVENT => {
BuiltInEvent::trigger_tcp_event(event_mgr.clone(), session.clone());
}
- PacketEvent::UDP_EVENT => {
+ PacketEvent::L4_UDP_EVENT => {
BuiltInEvent::trigger_udp_event(event_mgr.clone(), session.clone());
}
- PacketEvent::ICMP_EVENT => {
+ PacketEvent::L4_ICMP_EVENT => {
// TODO
}
- PacketEvent::ICMPV6_EVENT => {
+ PacketEvent::L4_ICMPV6_EVENT => {
// TODO
}
}
diff --git a/src/packet/error.rs b/src/packet/error.rs
index eda7e4c..744c6e8 100644
--- a/src/packet/error.rs
+++ b/src/packet/error.rs
@@ -5,6 +5,8 @@ pub enum PacketError {
// L2
IncompleteEthernetFrame,
IncompleteVlanHeader,
+ IncompleteMplsHeader,
+ IncompletePwEthHeader,
UnsupportEthernetType,
// L3
@@ -30,6 +32,8 @@ impl core::fmt::Display for PacketError {
// L2
PacketError::IncompleteEthernetFrame => write!(f, "Incomplete Ethernet Frame"),
PacketError::IncompleteVlanHeader => write!(f, "Incomplete VLAN Header"),
+ PacketError::IncompleteMplsHeader => write!(f, "Incomplete MPLS Header"),
+ PacketError::IncompletePwEthHeader => write!(f, "Incomplete PW Ethernet Header"),
PacketError::UnsupportEthernetType => write!(f, "Unsupport Ethernet Type"),
// L3
PacketError::IncompleteIpv4Header => write!(f, "Incomplete IPv4 Header"),
diff --git a/src/packet/packet.rs b/src/packet/packet.rs
index 84f75f1..3722057 100644
--- a/src/packet/packet.rs
+++ b/src/packet/packet.rs
@@ -7,6 +7,8 @@ use crate::protocol::icmpv6::Icmpv6Header;
use crate::protocol::ip::IPProtocol;
use crate::protocol::ipv4::IPv4Header;
use crate::protocol::ipv6::IPv6Header;
+use crate::protocol::mpls::MplsHeader;
+use crate::protocol::mpls::PwEthHeader;
use crate::protocol::tcp::TcpHeader;
use crate::protocol::udp::UdpHeader;
use crate::protocol::vlan::VlanHeader;
@@ -16,6 +18,8 @@ use crate::protocol::vlan::VlanHeader;
pub enum Encapsulation<'a> {
L2_ETH(EthernetFrame, &'a [u8]),
L2_VLAN(VlanHeader, &'a [u8]),
+ L2_MPLS(MplsHeader, &'a [u8]),
+ L2_PWETH(PwEthHeader, &'a [u8]),
L3_IPV4(IPv4Header, &'a [u8]),
L3_IPV6(IPv6Header, &'a [u8]),
@@ -33,19 +37,21 @@ pub enum Encapsulation<'a> {
pub enum PacketEvent {
// L2 Layer Event
L2_EVENT,
- L2_VLAN,
+ L2_VLAN_EVENT,
+ L2_MPLS_EVENT,
+ L2_PWETH_EVENT,
// L3 Layer Event
L3_EVENT,
- IPV4_EVENT,
- IPV6_EVENT,
+ L3_IPV4_EVENT,
+ L3_IPV6_EVENT,
// L4 Layer Event
L4_EVENT,
- TCP_EVENT,
- UDP_EVENT,
- ICMP_EVENT,
- ICMPV6_EVENT,
+ L4_TCP_EVENT,
+ L4_UDP_EVENT,
+ L4_ICMP_EVENT,
+ L4_ICMPV6_EVENT,
}
#[derive(Debug)]
@@ -386,6 +392,58 @@ fn handle_l3<'a>(
next_proto: EtherType,
) -> Result<(), PacketError> {
match next_proto {
+ EtherType::MPLSuni => {
+ let result = MplsHeader::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+
+ 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 payload.len() < 1 {
+ return Ok(());
+ }
+
+ let next_proto = payload[0] >> 4;
+ match next_proto {
+ 0x0 => {
+ let result = PwEthHeader::decode(payload);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+
+ packet
+ .encapsulation
+ .push(Encapsulation::L2_PWETH(header, payload));
+
+ packet.event.push(PacketEvent::L2_EVENT);
+ packet.event.push(PacketEvent::L2_PWETH_EVENT);
+ return handle_l2(packet, payload);
+ } else {
+ return Err(PacketError::IncompletePwEthHeader);
+ }
+ }
+ 0x4 => {
+ return handle_l3(packet, payload, EtherType::IPv4);
+ }
+ 0x6 => {
+ return handle_l3(packet, payload, EtherType::IPv6);
+ }
+ _ => {
+ return handle_l2(packet, payload);
+ }
+ }
+ } else {
+ return handle_l3(packet, payload, EtherType::MPLSuni);
+ }
+ } else {
+ return Err(PacketError::IncompleteMplsHeader);
+ }
+ }
EtherType::QinQ | EtherType::VLAN => {
let result = VlanHeader::decode(input);
if let Ok((payload, header)) = result {
@@ -396,7 +454,7 @@ fn handle_l3<'a>(
.push(Encapsulation::L2_VLAN(header, payload));
packet.event.push(PacketEvent::L2_EVENT);
- packet.event.push(PacketEvent::L2_VLAN);
+ packet.event.push(PacketEvent::L2_VLAN_EVENT);
return handle_l3(packet, payload, header.ether_type);
} else {
return Err(PacketError::IncompleteVlanHeader);
@@ -407,10 +465,6 @@ fn handle_l3<'a>(
if let Ok((payload, header)) = result {
dbg!(&header);
- if header.length < input.len() as u16 {
- return Err(PacketError::InvalidIpv4HeaderLength);
- }
-
packet
.encapsulation
.push(Encapsulation::L3_IPV4(header, payload));
@@ -418,7 +472,7 @@ fn handle_l3<'a>(
// TODO IPv4 Fragment
packet.event.push(PacketEvent::L3_EVENT);
- packet.event.push(PacketEvent::IPV4_EVENT);
+ packet.event.push(PacketEvent::L3_IPV4_EVENT);
return handle_l4(packet, payload, header.protocol);
} else {
return Err(PacketError::IncompleteIpv4Header);
@@ -429,10 +483,6 @@ fn handle_l3<'a>(
if let Ok((payload, header)) = result {
dbg!(&header);
- if header.length < payload.len() as u16 {
- return Err(PacketError::InvalidIpv6HeaderLength);
- }
-
packet
.encapsulation
.push(Encapsulation::L3_IPV6(header, payload));
@@ -440,7 +490,7 @@ fn handle_l3<'a>(
// TODO IPv6 Fragment
packet.event.push(PacketEvent::L3_EVENT);
- packet.event.push(PacketEvent::IPV6_EVENT);
+ packet.event.push(PacketEvent::L3_IPV6_EVENT);
return handle_l4(packet, payload, header.next_header);
} else {
return Err(PacketError::IncompleteIpv6Header);
@@ -474,7 +524,7 @@ fn handle_l4<'a>(
.push(Encapsulation::L4_ICMP(header, payload));
packet.event.push(PacketEvent::L4_EVENT);
- packet.event.push(PacketEvent::ICMP_EVENT);
+ packet.event.push(PacketEvent::L4_ICMP_EVENT);
return Ok(());
} else {
return Err(PacketError::IncompleteIcmpHeader);
@@ -490,7 +540,7 @@ fn handle_l4<'a>(
.push(Encapsulation::L4_ICMPV6(header, payload));
packet.event.push(PacketEvent::L4_EVENT);
- packet.event.push(PacketEvent::ICMPV6_EVENT);
+ packet.event.push(PacketEvent::L4_ICMPV6_EVENT);
return Ok(());
} else {
return Err(PacketError::IncompleteIcmpv6Header);
@@ -506,7 +556,7 @@ fn handle_l4<'a>(
.push(Encapsulation::L4_UDP(header, payload));
packet.event.push(PacketEvent::L4_EVENT);
- packet.event.push(PacketEvent::UDP_EVENT);
+ packet.event.push(PacketEvent::L4_UDP_EVENT);
return Ok(());
} else {
return Err(PacketError::IncompleteUdpHeader);
@@ -524,7 +574,7 @@ fn handle_l4<'a>(
// TODO TCP Reassembly
packet.event.push(PacketEvent::L4_EVENT);
- packet.event.push(PacketEvent::TCP_EVENT);
+ packet.event.push(PacketEvent::L4_TCP_EVENT);
return Ok(());
} else {
return Err(PacketError::IncompleteTcpHeader);
@@ -547,10 +597,15 @@ mod tests {
use crate::protocol::ethernet::EtherType;
use crate::protocol::ethernet::EthernetFrame;
use crate::protocol::ethernet::MacAddress;
+ use crate::protocol::icmp::IcmpHeader;
+ use crate::protocol::icmp::IcmpType;
use crate::protocol::ip::IPProtocol;
use crate::protocol::ipv4::IPv4Header;
use crate::protocol::ipv6::IPv6Header;
+ use crate::protocol::mpls::MplsHeader;
+ use crate::protocol::mpls::PwEthHeader;
use crate::protocol::tcp::TcpHeader;
+ use crate::protocol::tcp::TcpOption;
use crate::protocol::udp::UdpHeader;
use crate::protocol::vlan::VlanHeader;
use std::net::Ipv4Addr;
@@ -1893,4 +1948,398 @@ mod tests {
// assert_eq!(1, 0);
}
+
+ #[test]
+ fn test_packet_handle_eth_mpls_mpls_ipv4_tcp() {
+ /*
+ * Frame 1: 66 bytes on wire (528 bits), 66 bytes captured (528 bits)
+ * Encapsulation type: Ethernet (1)
+ * Arrival Time: Mar 4, 2000 05:27:46.896814000 CST
+ * [Time shift for this packet: 0.000000000 seconds]
+ * Epoch Time: 952118866.896814000 seconds
+ * [Time delta from previous captured frame: 0.000000000 seconds]
+ * [Time delta from previous displayed frame: 0.000000000 seconds]
+ * [Time since reference or first frame: 0.000000000 seconds]
+ * Frame Number: 1
+ * Frame Length: 66 bytes (528 bits)
+ * Capture Length: 66 bytes (528 bits)
+ * [Frame is marked: False]
+ * [Frame is ignored: False]
+ * [Protocols in frame: eth:ethertype:mpls:ip:tcp]
+ * [Coloring Rule Name: TCP SYN/FIN]
+ * [Coloring Rule String: tcp.flags & 0x02 || tcp.flags.fin == 1]
+ * Ethernet II, Src: Cisco_05:28:38 (00:30:96:05:28:38), Dst: Cisco_e6:fc:39 (00:30:96:e6:fc:39)
+ * Destination: Cisco_e6:fc:39 (00:30:96:e6:fc:39)
+ * Address: Cisco_e6:fc:39 (00:30:96:e6:fc:39)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Source: Cisco_05:28:38 (00:30:96:05:28:38)
+ * Address: Cisco_05:28:38 (00:30:96:05:28:38)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Type: MPLS label switched packet (0x8847)
+ * MultiProtocol Label Switching Header, Label: 18, Exp: 5, S: 0, TTL: 255
+ * 0000 0000 0000 0001 0010 .... .... .... = MPLS Label: 18 (0x00012)
+ * .... .... .... .... .... 101. .... .... = MPLS Experimental Bits: 5
+ * .... .... .... .... .... ...0 .... .... = MPLS Bottom Of Label Stack: 0
+ * .... .... .... .... .... .... 1111 1111 = MPLS TTL: 255
+ * MultiProtocol Label Switching Header, Label: 16, Exp: 5, S: 1, TTL: 255
+ * 0000 0000 0000 0001 0000 .... .... .... = MPLS Label: 16 (0x00010)
+ * .... .... .... .... .... 101. .... .... = MPLS Experimental Bits: 5
+ * .... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
+ * .... .... .... .... .... .... 1111 1111 = MPLS TTL: 255
+ * Internet Protocol Version 4, Src: 10.31.0.1, Dst: 10.34.0.1
+ * 0100 .... = Version: 4
+ * .... 0101 = Header Length: 20 bytes (5)
+ * Differentiated Services Field: 0xb0 (DSCP: Unknown, ECN: Not-ECT)
+ * 1011 00.. = Differentiated Services Codepoint: Unknown (44)
+ * .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
+ * Total Length: 44
+ * Identification: 0x0000 (0)
+ * 000. .... = Flags: 0x0
+ * 0... .... = Reserved bit: Not set
+ * .0.. .... = Don't fragment: Not set
+ * ..0. .... = More fragments: Not set
+ * ...0 0000 0000 0000 = Fragment Offset: 0
+ * Time to Live: 255
+ * Protocol: TCP (6)
+ * Header Checksum: 0xa6d9 [correct]
+ * [Header checksum status: Good]
+ * [Calculated Checksum: 0xa6d9]
+ * Source Address: 10.31.0.1
+ * Destination Address: 10.34.0.1
+ * Transmission Control Protocol, Src Port: 11001, Dst Port: 23, Seq: 0, Len: 0
+ * Source Port: 11001
+ * Destination Port: 23
+ * [Stream index: 0]
+ * [Conversation completeness: Incomplete (29)]
+ * [TCP Segment Len: 0]
+ * Sequence Number: 0 (relative sequence number)
+ * Sequence Number (raw): 3481568569
+ * [Next Sequence Number: 1 (relative sequence number)]
+ * Acknowledgment Number: 0
+ * Acknowledgment number (raw): 0
+ * 0110 .... = Header Length: 24 bytes (6)
+ * Flags: 0x002 (SYN)
+ * 000. .... .... = Reserved: Not set
+ * ...0 .... .... = Accurate ECN: Not set
+ * .... 0... .... = Congestion Window Reduced: Not set
+ * .... .0.. .... = ECN-Echo: Not set
+ * .... ..0. .... = Urgent: Not set
+ * .... ...0 .... = Acknowledgment: Not set
+ * .... .... 0... = Push: Not set
+ * .... .... .0.. = Reset: Not set
+ * .... .... ..1. = Syn: Set
+ * [Expert Info (Chat/Sequence): Connection establish request (SYN): server port 23]
+ * [Connection establish request (SYN): server port 23]
+ * [Severity level: Chat]
+ * [Group: Sequence]
+ * .... .... ...0 = Fin: Not set
+ * [TCP Flags: ··········S·]
+ * Window: 4128
+ * [Calculated window size: 4128]
+ * Checksum: 0xf791 [correct]
+ * [Checksum Status: Good]
+ * [Calculated Checksum: 0xf791]
+ * Urgent Pointer: 0
+ * Options: (4 bytes), Maximum segment size
+ * TCP Option - Maximum segment size: 536 bytes
+ * Kind: Maximum Segment Size (2)
+ * Length: 4
+ * MSS Value: 536
+ * [Timestamps]
+ * [Time since first frame in this TCP stream: 0.000000000 seconds]
+ * [Time since previous frame in this TCP stream: 0.000000000 seconds]
+ */
+
+ let bytes = [
+ 0x00, 0x30, 0x96, 0xe6, 0xfc, 0x39, 0x00, 0x30, 0x96, 0x05, 0x28, 0x38, 0x88, 0x47,
+ 0x00, 0x01, 0x2a, 0xff, 0x00, 0x01, 0x0b, 0xff, 0x45, 0xb0, 0x00, 0x2c, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x06, 0xa6, 0xd9, 0x0a, 0x1f, 0x00, 0x01, 0x0a, 0x22, 0x00, 0x01,
+ 0x2a, 0xf9, 0x00, 0x17, 0xcf, 0x84, 0x85, 0x39, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02,
+ 0x10, 0x20, 0xf7, 0x91, 0x00, 0x00, 0x02, 0x04, 0x02, 0x18,
+ ];
+
+ let mut packet = Packet::new(&bytes, bytes.len() as u32);
+ let result = packet.handle();
+ assert_eq!(result.is_ok(), true);
+
+ assert_eq!(packet.encapsulation.len(), 5);
+ assert_eq!(
+ packet.encapsulation[0],
+ Encapsulation::L2_ETH(
+ EthernetFrame {
+ source_mac: MacAddress([0x00, 0x30, 0x96, 0x05, 0x28, 0x38]),
+ dest_mac: MacAddress([0x00, 0x30, 0x96, 0xe6, 0xfc, 0x39]),
+ ether_type: EtherType::MPLSuni,
+ },
+ &bytes[14..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[1],
+ Encapsulation::L2_MPLS(
+ MplsHeader {
+ label: 18,
+ experimental: 5,
+ bottom_of_stack: false,
+ ttl: 255,
+ },
+ &bytes[18..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[2],
+ Encapsulation::L2_MPLS(
+ MplsHeader {
+ label: 16,
+ experimental: 5,
+ bottom_of_stack: true,
+ ttl: 255,
+ },
+ &bytes[22..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[3],
+ Encapsulation::L3_IPV4(
+ IPv4Header {
+ version: 4,
+ ihl: 20,
+ tos: 0xb0,
+ length: 44,
+ id: 0x0000,
+ flags: 0x0,
+ frag_offset: 0,
+ ttl: 255,
+ protocol: IPProtocol::TCP,
+ checksum: 0xa6d9,
+ source_address: Ipv4Addr::new(10, 31, 0, 1),
+ dest_address: Ipv4Addr::new(10, 34, 0, 1),
+ },
+ &bytes[42..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[4],
+ Encapsulation::L4_TCP(
+ TcpHeader {
+ source_port: 11001,
+ dest_port: 23,
+ seq_num: 3481568569,
+ ack_num: 0,
+ data_offset: 24,
+ reserved: 0,
+ flag_urg: false,
+ flag_ack: false,
+ flag_psh: false,
+ flag_rst: false,
+ flag_syn: true,
+ flag_fin: false,
+ window: 4128,
+ checksum: 0xf791,
+ urgent_ptr: 0,
+ options: Some(vec![TcpOption::MSS {
+ length: 4,
+ mss: 536
+ }]),
+ },
+ &bytes[66..]
+ )
+ );
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ fn test_packet_handle_eth_mpls_pw_mpls_eth_ipv4_icmp() {
+ /*
+ * Frame 3: 154 bytes on wire (1232 bits), 154 bytes captured (1232 bits)
+ * Encapsulation type: Ethernet (1)
+ * Arrival Time: Oct 13, 2009 02:09:16.301821000 CST
+ * [Time shift for this packet: 0.000000000 seconds]
+ * Epoch Time: 1255370956.301821000 seconds
+ * [Time delta from previous captured frame: 0.891000000 seconds]
+ * [Time delta from previous displayed frame: 0.891000000 seconds]
+ * [Time since reference or first frame: 0.969000000 seconds]
+ * Frame Number: 3
+ * Frame Length: 154 bytes (1232 bits)
+ * Capture Length: 154 bytes (1232 bits)
+ * [Frame is marked: False]
+ * [Frame is ignored: False]
+ * [Protocols in frame: eth:ethertype:mpls:pwethheuristic:pwethcw:eth:ethertype:ip:icmp:data]
+ * [Coloring Rule Name: ICMP]
+ * [Coloring Rule String: icmp || icmpv6]
+ * Ethernet II, Src: cc:01:0d:5c:00:10 (cc:01:0d:5c:00:10), Dst: cc:00:0d:5c:00:10 (cc:00:0d:5c:00:10)
+ * Destination: cc:00:0d:5c:00:10 (cc:00:0d:5c:00:10)
+ * Address: cc:00:0d:5c:00:10 (cc:00:0d:5c:00:10)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Source: cc:01:0d:5c:00:10 (cc:01:0d:5c:00:10)
+ * Address: cc:01:0d:5c:00:10 (cc:01:0d:5c:00:10)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Type: MPLS label switched packet (0x8847)
+ * MultiProtocol Label Switching Header, Label: 19, Exp: 0, S: 0, TTL: 254
+ * 0000 0000 0000 0001 0011 .... .... .... = MPLS Label: 19 (0x00013)
+ * .... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
+ * .... .... .... .... .... ...0 .... .... = MPLS Bottom Of Label Stack: 0
+ * .... .... .... .... .... .... 1111 1110 = MPLS TTL: 254
+ * MultiProtocol Label Switching Header, Label: 16, Exp: 0, S: 1, TTL: 255
+ * 0000 0000 0000 0001 0000 .... .... .... = MPLS Label: 16 (0x00010)
+ * .... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
+ * .... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
+ * .... .... .... .... .... .... 1111 1111 = MPLS TTL: 255
+ * PW Ethernet Control Word
+ * Sequence Number: 0
+ * Ethernet II, Src: Private_66:68:00 (00:50:79:66:68:00), Dst: Private_66:68:01 (00:50:79:66:68:01)
+ * Destination: Private_66:68:01 (00:50:79:66:68:01)
+ * Address: Private_66:68:01 (00:50:79:66:68:01)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Source: Private_66:68:00 (00:50:79:66:68:00)
+ * Address: Private_66:68:00 (00:50:79:66:68:00)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Type: IPv4 (0x0800)
+ * Trailer: 000000000000000000000000000000000000000000000000000000000000
+ * Internet Protocol Version 4, Src: 192.168.0.10, Dst: 192.168.0.20
+ * 0100 .... = Version: 4
+ * .... 0101 = Header Length: 20 bytes (5)
+ * Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
+ * 0000 00.. = Differentiated Services Codepoint: Default (0)
+ * .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
+ * Total Length: 84
+ * Identification: 0xcc70 (52336)
+ * 010. .... = Flags: 0x2, Don't fragment
+ * 0... .... = Reserved bit: Not set
+ * .1.. .... = Don't fragment: Set
+ * ..0. .... = More fragments: Not set
+ * ...0 0000 0000 0000 = Fragment Offset: 0
+ * Time to Live: 64
+ * Protocol: ICMP (1)
+ * Header Checksum: 0xecc9 [correct]
+ * [Header checksum status: Good]
+ * [Calculated Checksum: 0xecc9]
+ * Source Address: 192.168.0.10
+ * Destination Address: 192.168.0.20
+ * Internet Control Message Protocol
+ * Type: 8 (Echo (ping) request)
+ * Code: 0
+ * Checksum: 0x529b [correct]
+ * [Checksum Status: Good]
+ * Identifier (BE): 52336 (0xcc70)
+ * Identifier (LE): 28876 (0x70cc)
+ * Sequence Number (BE): 256 (0x0100)
+ * Sequence Number (LE): 1 (0x0001)
+ * [Response frame: 4]
+ * Data (56 bytes)
+ * Data: 08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b…
+ * [Length: 56]
+ */
+
+ let bytes = [
+ 0xcc, 0x00, 0x0d, 0x5c, 0x00, 0x10, 0xcc, 0x01, 0x0d, 0x5c, 0x00, 0x10, 0x88, 0x47,
+ 0x00, 0x01, 0x30, 0xfe, 0x00, 0x01, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+ 0x79, 0x66, 0x68, 0x01, 0x00, 0x50, 0x79, 0x66, 0x68, 0x00, 0x08, 0x00, 0x45, 0x00,
+ 0x00, 0x54, 0xcc, 0x70, 0x40, 0x00, 0x40, 0x01, 0xec, 0xc9, 0xc0, 0xa8, 0x00, 0x0a,
+ 0xc0, 0xa8, 0x00, 0x14, 0x08, 0x00, 0x52, 0x9b, 0xcc, 0x70, 0x01, 0x00, 0x08, 0x09,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ let mut packet = Packet::new(&bytes, bytes.len() as u32);
+ let result = packet.handle();
+ assert_eq!(result.is_ok(), true);
+
+ assert_eq!(packet.encapsulation.len(), 7);
+ assert_eq!(
+ packet.encapsulation[0],
+ Encapsulation::L2_ETH(
+ EthernetFrame {
+ source_mac: MacAddress([0xcc, 0x01, 0x0d, 0x5c, 0x00, 0x10]),
+ dest_mac: MacAddress([0xcc, 0x00, 0x0d, 0x5c, 0x00, 0x10]),
+ ether_type: EtherType::MPLSuni,
+ },
+ &bytes[14..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[1],
+ Encapsulation::L2_MPLS(
+ MplsHeader {
+ label: 19,
+ experimental: 0,
+ bottom_of_stack: false,
+ ttl: 254,
+ },
+ &bytes[18..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[2],
+ Encapsulation::L2_MPLS(
+ MplsHeader {
+ label: 16,
+ experimental: 0,
+ bottom_of_stack: true,
+ ttl: 255,
+ },
+ &bytes[22..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[3],
+ Encapsulation::L2_PWETH(PwEthHeader { control_word: 0 }, &bytes[26..])
+ );
+ assert_eq!(
+ packet.encapsulation[4],
+ Encapsulation::L2_ETH(
+ EthernetFrame {
+ source_mac: MacAddress([0x00, 0x50, 0x79, 0x66, 0x68, 0x00]),
+ dest_mac: MacAddress([0x00, 0x50, 0x79, 0x66, 0x68, 0x01]),
+ ether_type: EtherType::IPv4,
+ },
+ &bytes[40..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[5],
+ Encapsulation::L3_IPV4(
+ IPv4Header {
+ version: 4,
+ ihl: 20,
+ tos: 0x00,
+ length: 84,
+ id: 0xcc70,
+ flags: 0x2,
+ frag_offset: 0,
+ ttl: 64,
+ protocol: IPProtocol::ICMP,
+ checksum: 0xecc9,
+ source_address: Ipv4Addr::new(192, 168, 0, 10),
+ dest_address: Ipv4Addr::new(192, 168, 0, 20),
+ },
+ &bytes[60..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[6],
+ Encapsulation::L4_ICMP(
+ IcmpHeader {
+ icmp_type: IcmpType::EchoRequest,
+ icmp_code: 0,
+ icmp_checksum: 0x529b,
+ icmp_extended: vec![0xcc, 0x70, 0x01, 0x00],
+ },
+ &bytes[68..]
+ )
+ );
+
+ // assert_eq!(1, 0);
+ }
}
diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs
index c82e203..36f0ae6 100644
--- a/src/protocol/mod.rs
+++ b/src/protocol/mod.rs
@@ -9,4 +9,5 @@ pub mod dns;
pub mod http;
pub mod vlan;
pub mod icmp;
-pub mod icmpv6; \ No newline at end of file
+pub mod icmpv6;
+pub mod mpls; \ No newline at end of file
diff --git a/src/protocol/mpls.rs b/src/protocol/mpls.rs
new file mode 100644
index 0000000..2c4c443
--- /dev/null
+++ b/src/protocol/mpls.rs
@@ -0,0 +1,123 @@
+use crate::protocol::codec::Decode;
+use nom::bits;
+use nom::error::Error;
+use nom::number;
+use nom::sequence;
+use nom::IResult;
+
+/******************************************************************************
+ * Struct
+ ******************************************************************************/
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct MplsHeader {
+ pub label: u32,
+ pub experimental: u8,
+ pub bottom_of_stack: bool,
+ pub ttl: u8,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+// Ethernet pseudowire (PW) https://tools.ietf.org/html/rfc4448#section-3.1
+pub struct PwEthHeader {
+ pub control_word: u32,
+}
+
+/******************************************************************************
+ * API
+ ******************************************************************************/
+
+fn bit_decode(input: &[u8]) -> IResult<&[u8], (u32, u8, u8, u8)> {
+ bits::bits::<_, _, Error<_>, _, _>(sequence::tuple((
+ bits::streaming::take(20u8),
+ bits::streaming::take(3u8),
+ bits::streaming::take(1u8),
+ bits::streaming::take(8u8),
+ )))(input)
+}
+
+impl Decode for MplsHeader {
+ type Iterm = MplsHeader;
+ fn decode(input: &[u8]) -> IResult<&[u8], MplsHeader> {
+ let (input, (label, experimental, bottom_of_stack, ttl)) = bit_decode(input)?;
+
+ Ok((
+ input,
+ MplsHeader {
+ label,
+ experimental,
+ bottom_of_stack: bottom_of_stack == 1,
+ ttl,
+ },
+ ))
+ }
+}
+
+impl Decode for PwEthHeader {
+ type Iterm = PwEthHeader;
+ fn decode(input: &[u8]) -> IResult<&[u8], PwEthHeader> {
+ let (input, control_word) = number::streaming::be_u32(input)?;
+
+ Ok((input, PwEthHeader { control_word }))
+ }
+}
+
+/******************************************************************************
+ * TEST
+ ******************************************************************************/
+
+#[cfg(test)]
+mod tests {
+ use super::MplsHeader;
+ use crate::protocol::codec::Decode;
+ const LAST_SLICE: &'static [u8] = &[0xff];
+
+ #[test]
+ fn mpls_header_decode() {
+ /*
+ * MultiProtocol Label Switching Header, Label: 18, Exp: 5, S: 0, TTL: 255
+ * 0000 0000 0000 0001 0010 .... .... .... = MPLS Label: 18 (0x00012)
+ * .... .... .... .... .... 101. .... .... = MPLS Experimental Bits: 5
+ * .... .... .... .... .... ...0 .... .... = MPLS Bottom Of Label Stack: 0
+ * .... .... .... .... .... .... 1111 1111 = MPLS TTL: 255
+ * MultiProtocol Label Switching Header, Label: 16, Exp: 5, S: 1, TTL: 255
+ * 0000 0000 0000 0001 0000 .... .... .... = MPLS Label: 16 (0x00010)
+ * .... .... .... .... .... 101. .... .... = MPLS Experimental Bits: 5
+ * .... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
+ * .... .... .... .... .... .... 1111 1111 = MPLS TTL: 255
+ */
+
+ let bytes = [0x00, 0x01, 0x2a, 0xff, 0x00, 0x01, 0x0b, 0xff, 0xff];
+
+ let expectation1 = MplsHeader {
+ label: 18,
+ experimental: 5,
+ bottom_of_stack: false,
+ ttl: 255,
+ };
+ let expectation2 = MplsHeader {
+ label: 16,
+ experimental: 5,
+ bottom_of_stack: true,
+ ttl: 255,
+ };
+
+ assert_eq!(MplsHeader::decode(&bytes), Ok((&bytes[4..], expectation1)));
+ assert_eq!(
+ MplsHeader::decode(&bytes[4..]),
+ Ok((LAST_SLICE, expectation2))
+ );
+
+ // example
+ let mut payload = &bytes[..];
+ while let Ok((remain, header)) = MplsHeader::decode(payload) {
+ println!("return: {:?}, payload: {}", header, remain.len());
+ payload = remain;
+ if header.bottom_of_stack {
+ break;
+ }
+ }
+
+ // assert_eq!(1, 0);
+ }
+}