From 3e2300a6abc592862397f66d66c8a2c811fc2ae4 Mon Sep 17 00:00:00 2001 From: luwenpeng Date: Mon, 25 Sep 2023 15:11:01 +0800 Subject: [feature] Support PPPoE Decode --- src/main.rs | 20 +- src/packet/error.rs | 96 +++--- src/packet/packet.rs | 771 ++++++++++++++++++++++++++++++++++------------- src/protocol/ethernet.rs | 15 +- src/protocol/grev0.rs | 26 +- src/protocol/grev1.rs | 13 +- src/protocol/gtpv1.rs | 22 +- src/protocol/icmp.rs | 11 +- src/protocol/icmpv6.rs | 11 +- src/protocol/ipv4.rs | 13 +- src/protocol/ipv6.rs | 46 ++- src/protocol/l2tp.rs | 44 ++- src/protocol/mod.rs | 3 +- src/protocol/ppp.rs | 13 +- src/protocol/pppoe.rs | 252 ++++++++++++++++ src/protocol/pptp.rs | 121 +++++--- src/protocol/udp.rs | 13 +- src/protocol/vlan.rs | 13 +- 18 files changed, 1120 insertions(+), 383 deletions(-) create mode 100644 src/protocol/pppoe.rs diff --git a/src/main.rs b/src/main.rs index 78d5e8d..3dcc273 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,6 +69,9 @@ fn trigger_packet_event( Encapsulation::PPP(_, _) => { // TODO } + Encapsulation::PPPoE(_, _) => { + // TODO + } } } } @@ -139,13 +142,16 @@ fn handle_one_packet(data: &[u8], len: u32, thread_ctx: &mut ThreadContext) { } } - if packet.get_inner_most_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()), &mut queue); - trigger_session_event(Some(session.clone()), &mut queue); - } else { - trigger_packet_event(&packet, None, &mut queue); + match packet.get_inner_most_tuple() { + 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()), &mut queue); + trigger_session_event(Some(session.clone()), &mut queue); + } + None => { + trigger_packet_event(&packet, None, &mut queue); + } } event_mgr.borrow_mut().dispatch(Some(&packet), &mut queue); diff --git a/src/packet/error.rs b/src/packet/error.rs index 9566ce9..38103ed 100644 --- a/src/packet/error.rs +++ b/src/packet/error.rs @@ -3,42 +3,42 @@ pub enum PacketError { InvalidPacketLength, // L2 - IncompleteEthernetFrame, - IncompleteVlanHeader, - IncompleteMplsHeader, - IncompletePwEthHeader, UnsupportEthernetType, + IncompleteEthernetFrame, - // L3 - IncompleteIpv4Header, - IncompleteIpv6Header, - - InvalidIpv4HeaderLength, - InvalidIpv6HeaderLength, + IncompleteVLANHeader, + IncompleteMPLSHeader, + IncompletePWEthernetHeader, + // L3 UnsupportIPProtocol, + IncompleteIPv4Header, + IncompleteIPv6Header, // L3.5 - IncompleteGreHeader, - IncompleteGrev0Header, - IncompleteGrev1Header, - UnsupportGreVersion, + UnsupportGREVersion, + IncompleteGREHeader, + IncompleteGREv0Header, + IncompleteGREv1Header, // L4 - IncompleteUdpHeader, - IncompleteTcpHeader, - IncompleteIcmpHeader, - IncompleteIcmpv6Header, + IncompleteUDPHeader, + IncompleteTCPHeader, + IncompleteICMPHeader, + IncompleteICMPv6Header, // L TUNNEL - IncompleteGtpv1Header, - UnsupportGtpVersion, + UnsupportGTPVersion, + IncompleteGTPv1Header, + + UnsupportL2TPVersion, + IncompleteL2TPHeader, - IncompleteL2tpHeader, - UnsupportL2tpVersion, + IncompletePPTPHeader, + IncompletePPPHeader, - IncompletePptpHeader, - IncompletePppHeader, + UnsupportPPPoEVersion, + IncompletePPPoEHeader, } impl core::fmt::Display for PacketError { @@ -46,34 +46,38 @@ impl core::fmt::Display for PacketError { match *self { PacketError::InvalidPacketLength => write!(f, "Invalid Packet Length"), // 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"), + PacketError::IncompleteEthernetFrame => write!(f, "Incomplete Ethernet Frame"), + + PacketError::IncompleteVLANHeader => write!(f, "Incomplete VLAN Header"), + PacketError::IncompleteMPLSHeader => write!(f, "Incomplete MPLS Header"), + PacketError::IncompletePWEthernetHeader => write!(f, "Incomplete PW Ethernet Header"), // L3 - PacketError::IncompleteIpv4Header => write!(f, "Incomplete IPv4 Header"), - PacketError::IncompleteIpv6Header => write!(f, "Incomplete IPv6 Header"), - PacketError::InvalidIpv4HeaderLength => write!(f, "Invalid IPv4 Header Length"), - PacketError::InvalidIpv6HeaderLength => write!(f, "Invalid IPv6 Header Length"), PacketError::UnsupportIPProtocol => write!(f, "Unsupport IP Protocol"), + PacketError::IncompleteIPv4Header => write!(f, "Incomplete IPv4 Header"), + PacketError::IncompleteIPv6Header => write!(f, "Incomplete IPv6 Header"), // L3.5 - PacketError::IncompleteGreHeader => write!(f, "Incomplete GRE Header"), - PacketError::IncompleteGrev0Header => write!(f, "Incomplete GREv0 Header"), - PacketError::IncompleteGrev1Header => write!(f, "Incomplete GREv1 Header"), - PacketError::UnsupportGreVersion => write!(f, "Unsupport GRE Version"), + PacketError::UnsupportGREVersion => write!(f, "Unsupport GRE Version"), + PacketError::IncompleteGREHeader => write!(f, "Incomplete GRE Header"), + PacketError::IncompleteGREv0Header => write!(f, "Incomplete GREv0 Header"), + PacketError::IncompleteGREv1Header => write!(f, "Incomplete GREv1 Header"), // L4 - PacketError::IncompleteUdpHeader => write!(f, "Incomplete UDP Header"), - PacketError::IncompleteTcpHeader => write!(f, "Incomplete TCP Header"), - PacketError::IncompleteIcmpHeader => write!(f, "Incomplete ICMP Header"), - PacketError::IncompleteIcmpv6Header => write!(f, "Incomplete ICMPv6 Header"), + PacketError::IncompleteUDPHeader => write!(f, "Incomplete UDP Header"), + PacketError::IncompleteTCPHeader => write!(f, "Incomplete TCP Header"), + PacketError::IncompleteICMPHeader => write!(f, "Incomplete ICMP Header"), + PacketError::IncompleteICMPv6Header => write!(f, "Incomplete ICMPv6 Header"), // L TUNNEL - PacketError::IncompleteGtpv1Header => write!(f, "Incomplete GTPv1 Header"), - PacketError::UnsupportGtpVersion => write!(f, "Unsupport GTP Version"), - PacketError::IncompleteL2tpHeader => write!(f, "Incomplete L2TP Header"), - PacketError::UnsupportL2tpVersion => write!(f, "Unsupport L2TP Version"), - PacketError::IncompletePptpHeader => write!(f, "Incomplete PPTP Header"), - PacketError::IncompletePppHeader => write!(f, "Incomplete PPP Header"), + PacketError::UnsupportGTPVersion => write!(f, "Unsupport GTP Version"), + PacketError::IncompleteGTPv1Header => write!(f, "Incomplete GTPv1 Header"), + + PacketError::UnsupportL2TPVersion => write!(f, "Unsupport L2TP Version"), + PacketError::IncompleteL2TPHeader => write!(f, "Incomplete L2TP Header"), + + PacketError::IncompletePPTPHeader => write!(f, "Incomplete PPTP Header"), + PacketError::IncompletePPPHeader => write!(f, "Incomplete PPP Header"), + + PacketError::UnsupportPPPoEVersion => write!(f, "Unsupport PPPoE Version"), + PacketError::IncompletePPPoEHeader => write!(f, "Incomplete PPPoE Header"), } } } diff --git a/src/packet/packet.rs b/src/packet/packet.rs index 8d258d5..d45c28d 100644 --- a/src/packet/packet.rs +++ b/src/packet/packet.rs @@ -16,6 +16,8 @@ use crate::protocol::mpls::MPLSHeader; use crate::protocol::mpls::PWEthHeader; use crate::protocol::ppp::PPPHeader; use crate::protocol::ppp::PPPProtocol; +use crate::protocol::pppoe::PPPoEHeader; +use crate::protocol::pppoe::PPPoEStage; use crate::protocol::pptp::PPTPHeader; use crate::protocol::tcp::TCPHeader; use crate::protocol::udp::UDPHeader; @@ -44,6 +46,7 @@ pub enum Encapsulation<'a> { L2TP(L2TPHeader, &'a [u8]), PPTP(PPTPHeader, &'a [u8]), PPP(PPPHeader, &'a [u8]), + PPPoE(PPPoEHeader, &'a [u8]), } #[derive(Debug)] @@ -64,9 +67,10 @@ impl Packet<'_> { pub fn handle(&mut self) -> Result<(), PacketError> { if self.orig_data.len() != self.orig_len as usize { - return Err(PacketError::InvalidPacketLength); + Err(PacketError::InvalidPacketLength) + } else { + handle_eth(self, self.orig_data) } - return handle_eth(self, self.orig_data); } pub fn get_outer_most_l3_layer(&self) -> Option { @@ -83,7 +87,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_inner_most_l3_layer(&self) -> Option { @@ -100,7 +104,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_outer_most_l4_layer(&self) -> Option { @@ -117,7 +121,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_inner_most_l4_layer(&self) -> Option { @@ -134,7 +138,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_outer_most_address(&self) -> Option<(String, String)> { @@ -157,7 +161,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_inner_most_address(&self) -> Option<(String, String)> { @@ -180,7 +184,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_outer_most_port(&self) -> Option<(u16, u16)> { @@ -197,7 +201,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_inner_most_port(&self) -> Option<(u16, u16)> { @@ -214,7 +218,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_outer_most_tuple(&self) -> Option<(String, u16, String, u16)> { @@ -266,7 +270,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_inner_most_tuple(&self) -> Option<(String, u16, String, u16)> { @@ -318,7 +322,7 @@ impl Packet<'_> { } } - return None; + None } pub fn get_flow_id(&self) -> Option { @@ -356,205 +360,217 @@ impl Packet<'_> { } } - Some(flow_id) + match flow_id.len() { + 0 => None, + _ => Some(flow_id), + } } } fn handle_eth<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = EthHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let next_proto = header.ether_type; - packet - .encapsulation - .push(Encapsulation::ETH(header, payload)); + let next_proto = header.ether_type; + packet + .encapsulation + .push(Encapsulation::ETH(header, payload)); - return handle_l3(packet, payload, next_proto); - } else { - return Err(PacketError::IncompleteEthernetFrame); + handle_l3(packet, payload, next_proto) + } + _ => Err(PacketError::IncompleteEthernetFrame), } } fn handle_vlan<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = VLANHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let next_proto = header.ether_type; - packet - .encapsulation - .push(Encapsulation::VLAN(header, payload)); + let next_proto = header.ether_type; + packet + .encapsulation + .push(Encapsulation::VLAN(header, payload)); - return handle_l3(packet, payload, next_proto); - } else { - return Err(PacketError::IncompleteVlanHeader); + handle_l3(packet, payload, next_proto) + } + _ => Err(PacketError::IncompleteVLANHeader), } } fn handle_mpls<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = MPLSHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let bottom_of_stack = header.bottom_of_stack; - packet - .encapsulation - .push(Encapsulation::MPLS(header, payload)); + let bottom_of_stack = header.bottom_of_stack; + packet + .encapsulation + .push(Encapsulation::MPLS(header, payload)); - if bottom_of_stack { - if payload.len() < 1 { - return Ok(()); - } + match bottom_of_stack { + true => { + if payload.len() < 1 { + return Ok(()); + } - let next_proto = payload[0] >> 4; - match next_proto { - 0x0 => handle_pw_eth(packet, payload), - 0x4 => handle_ipv4(packet, payload), - 0x6 => handle_ipv6(packet, payload), - _ => handle_eth(packet, payload), + let next_proto = payload[0] >> 4; + match next_proto { + 0x0 => handle_pw_eth(packet, payload), + 0x4 => handle_ipv4(packet, payload), + 0x6 => handle_ipv6(packet, payload), + _ => handle_eth(packet, payload), + } + } + false => handle_mpls(packet, payload), } - } else { - return handle_mpls(packet, payload); } - } else { - return Err(PacketError::IncompleteMplsHeader); + _ => Err(PacketError::IncompleteMPLSHeader), } } fn handle_pw_eth<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = PWEthHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - packet - .encapsulation - .push(Encapsulation::PWETH(header, payload)); + packet + .encapsulation + .push(Encapsulation::PWETH(header, payload)); - return handle_eth(packet, payload); - } else { - return Err(PacketError::IncompletePwEthHeader); + handle_eth(packet, payload) + } + _ => Err(PacketError::IncompletePWEthernetHeader), } } fn handle_ipv4<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = IPv4Header::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let next_proto = header.protocol; - packet - .encapsulation - .push(Encapsulation::IPv4(header, payload)); + let next_proto = header.protocol; + packet + .encapsulation + .push(Encapsulation::IPv4(header, payload)); - // TODO IPv4 Fragment + // TODO IPv4 Fragment - return handle_l4(packet, payload, next_proto); - } else { - return Err(PacketError::IncompleteIpv4Header); + handle_l4(packet, payload, next_proto) + } + _ => Err(PacketError::IncompleteIPv4Header), } } fn handle_ipv6<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = IPv6Header::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let mut next_proto = header.next_header; - for extension in header.extensions.iter() { - next_proto = extension.next_header; + let mut next_proto = header.next_header; + for extension in header.extensions.iter() { + next_proto = extension.next_header; - if next_proto == IPProtocol::IPV6FRAGMENT { - // TODO IPv6 Fragment + if next_proto == IPProtocol::IPV6FRAGMENT { + // TODO IPv6 Fragment + } } - } - packet - .encapsulation - .push(Encapsulation::IPv6(header, payload)); + packet + .encapsulation + .push(Encapsulation::IPv6(header, payload)); - return handle_l4(packet, payload, next_proto); - } else { - return Err(PacketError::IncompleteIpv6Header); + handle_l4(packet, payload, next_proto) + } + _ => Err(PacketError::IncompleteIPv6Header), } } fn handle_tcp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = TCPHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let source_port = header.source_port; - let dest_port = header.dest_port; - packet - .encapsulation - .push(Encapsulation::TCP(header, payload)); + let source_port = header.source_port; + let dest_port = header.dest_port; + packet + .encapsulation + .push(Encapsulation::TCP(header, payload)); - // TODO TCP Reassembly + // TODO TCP Reassembly - if payload.len() == 0 { - return Ok(()); - } + if payload.len() == 0 { + return Ok(()); + } - match (source_port, dest_port) { - // PPTP - (1723, _) | (_, 1723) => handle_pptp(packet, payload), - _ => Ok(()), + match (source_port, dest_port) { + // PPTP + (1723, _) | (_, 1723) => handle_pptp(packet, payload), + _ => Ok(()), + } } - } else { - return Err(PacketError::IncompleteTcpHeader); + _ => Err(PacketError::IncompleteTCPHeader), } } fn handle_udp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = UDPHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let dest_port = header.dest_port; - packet - .encapsulation - .push(Encapsulation::UDP(header, payload)); - - match dest_port { - // GTP-U - 2152 => handle_gtpv1(packet, payload), - // L2TPv2 - 1701 => handle_l2tp(packet, payload), - _ => Ok(()), + let dest_port = header.dest_port; + packet + .encapsulation + .push(Encapsulation::UDP(header, payload)); + + match dest_port { + 2152 => handle_gtpv1(packet, payload), // GTP-U + 1701 => handle_l2tp(packet, payload), // L2TPv2 + _ => Ok(()), + } } - } else { - return Err(PacketError::IncompleteUdpHeader); + _ => Err(PacketError::IncompleteUDPHeader), } } fn handle_icmp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = ICMPHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - packet - .encapsulation - .push(Encapsulation::ICMP(header, payload)); + packet + .encapsulation + .push(Encapsulation::ICMP(header, payload)); - return Ok(()); - } else { - return Err(PacketError::IncompleteIcmpHeader); + Ok(()) + } + _ => Err(PacketError::IncompleteICMPHeader), } } fn handle_icmpv6<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = ICMPv6Header::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - packet - .encapsulation - .push(Encapsulation::ICMPv6(header, payload)); + packet + .encapsulation + .push(Encapsulation::ICMPv6(header, payload)); - return Ok(()); - } else { - return Err(PacketError::IncompleteIcmpv6Header); + Ok(()) + } + _ => Err(PacketError::IncompleteICMPv6Header), } } @@ -579,12 +595,8 @@ fn handle_gtpv1<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Pack _ => Ok(()), } } - Err(Incomplete(_)) => { - return Err(PacketError::IncompleteGtpv1Header); - } - _ => { - return Err(PacketError::UnsupportGtpVersion); - } + Err(Incomplete(_)) => Err(PacketError::IncompleteGTPv1Header), + _ => Err(PacketError::UnsupportGTPVersion), } } @@ -600,104 +612,133 @@ fn handle_l2tp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packe .push(Encapsulation::L2TP(header, payload)); match l2tp_type { - L2TPType::Control => { - return Ok(()); - } - L2TPType::Data => { - return handle_ppp(packet, payload); - } + L2TPType::Control => Ok(()), + L2TPType::Data => handle_ppp(packet, payload), } } - Err(Incomplete(_)) => { - return Err(PacketError::IncompleteL2tpHeader); - } - _ => { - return Err(PacketError::UnsupportL2tpVersion); - } + Err(Incomplete(_)) => Err(PacketError::IncompleteL2TPHeader), + _ => Err(PacketError::UnsupportL2TPVersion), } } fn handle_gre<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { if input.len() < 2 { - return Err(PacketError::IncompleteGreHeader); + return Err(PacketError::IncompleteGREHeader); } let version = input[1] & 0x07; match version { 0 => { let result = GREv0Header::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let next_proto = header.protocol_type; - packet - .encapsulation - .push(Encapsulation::GREv0(header, payload)); + let next_proto = header.protocol_type; + packet + .encapsulation + .push(Encapsulation::GREv0(header, payload)); - return handle_l3(packet, payload, next_proto); - } else { - return Err(PacketError::IncompleteGrev0Header); + handle_l3(packet, payload, next_proto) + } + _ => Err(PacketError::IncompleteGREv0Header), } } 1 => { let result = GREv1Header::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let next_proto = header.protocol_type; - packet - .encapsulation - .push(Encapsulation::GREv1(header, payload)); + let next_proto = header.protocol_type; + packet + .encapsulation + .push(Encapsulation::GREv1(header, payload)); - return handle_l3(packet, payload, next_proto); - } else { - return Err(PacketError::IncompleteGrev1Header); + handle_l3(packet, payload, next_proto) + } + _ => Err(PacketError::IncompleteGREv1Header), } } - _ => { - return Err(PacketError::UnsupportGreVersion); - } + _ => Err(PacketError::UnsupportGREVersion), } } fn handle_pptp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = PPTPHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - packet - .encapsulation - .push(Encapsulation::PPTP(header, payload)); + packet + .encapsulation + .push(Encapsulation::PPTP(header, payload)); - return Ok(()); - } else { - return Err(PacketError::IncompletePptpHeader); + Ok(()) + } + _ => Err(PacketError::IncompletePPTPHeader), } } fn handle_ppp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { let result = PPPHeader::decode(input); - if let Ok((payload, header)) = result { - dbg!(&header); + match result { + Ok((payload, header)) => { + dbg!(&header); - let next_proto = header.protocol; - packet - .encapsulation - .push(Encapsulation::PPP(header, payload)); - - match next_proto { - // PPPProtocol::PAD => handle_pad(packet, payload), - PPPProtocol::IPv4 => handle_ipv4(packet, payload), - PPPProtocol::IPv6 => handle_ipv6(packet, payload), - // PPPProtocol::IPCP => handle_ipcp(packet, payload), - // PPPProtocol::CCP => handle_ccp(packet, payload), - // PPPProtocol::LCP => handle_lcp(packet, payload), - // PPPProtocol::PAP => handle_pap(packet, payload), - // PPPProtocol::CHAP => handle_chap(packet, payload), - _ => Ok(()), + let next_proto = header.protocol; + packet + .encapsulation + .push(Encapsulation::PPP(header, payload)); + + match next_proto { + // PPPProtocol::PAD => handle_pad(packet, payload), + PPPProtocol::IPv4 => handle_ipv4(packet, payload), + PPPProtocol::IPv6 => handle_ipv6(packet, payload), + // PPPProtocol::IPCP => handle_ipcp(packet, payload), + // PPPProtocol::CCP => handle_ccp(packet, payload), + // PPPProtocol::LCP => handle_lcp(packet, payload), + // PPPProtocol::PAP => handle_pap(packet, payload), + // PPPProtocol::CHAP => handle_chap(packet, payload), + _ => Ok(()), + } } - } else { - return Err(PacketError::IncompletePppHeader); + _ => Err(PacketError::IncompletePPPHeader), + } +} + +fn handle_pppoe<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> { + let result = PPPoEHeader::decode(input); + match result { + Ok((payload, header)) => { + dbg!(&header); + + let next_proto = match header.stage { + PPPoEStage::Session(next_proto) => Some(next_proto), + PPPoEStage::Discovery(_) => None, + }; + + packet + .encapsulation + .push(Encapsulation::PPPoE(header, payload)); + + match next_proto { + Some(next_proto) => match next_proto { + // PPPProtocol::PAD => handle_pad(packet, payload), + PPPProtocol::IPv4 => handle_ipv4(packet, payload), + PPPProtocol::IPv6 => handle_ipv6(packet, payload), + // PPPProtocol::IPCP => handle_ipcp(packet, payload), + // PPPProtocol::CCP => handle_ccp(packet, payload), + // PPPProtocol::LCP => handle_lcp(packet, payload), + // PPPProtocol::PAP => handle_pap(packet, payload), + // PPPProtocol::CHAP => handle_chap(packet, payload), + _ => Ok(()), + }, + None => Ok(()), + } + } + Err(Incomplete(_)) => Err(PacketError::IncompletePPPoEHeader), + _ => Err(PacketError::UnsupportPPPoEVersion), } } @@ -707,15 +748,15 @@ fn handle_l3<'a>( next_proto: EthType, ) -> Result<(), PacketError> { match next_proto { + EthType::PPPoEdiscovery => handle_pppoe(packet, input), + EthType::PPPoEsession => handle_pppoe(packet, input), EthType::PPP => handle_ppp(packet, input), EthType::MPLSuni => handle_mpls(packet, input), EthType::QinQ => handle_vlan(packet, input), EthType::VLAN => handle_vlan(packet, input), EthType::IPv4 => handle_ipv4(packet, input), EthType::IPv6 => handle_ipv6(packet, input), - _e => { - return Err(PacketError::UnsupportEthernetType); - } + _e => Err(PacketError::UnsupportEthernetType), } } @@ -732,9 +773,7 @@ fn handle_l4<'a>( IPProtocol::ICMP6 => handle_icmpv6(packet, input), IPProtocol::UDP => handle_udp(packet, input), IPProtocol::TCP => handle_tcp(packet, input), - _e => { - return Err(PacketError::UnsupportIPProtocol); - } + _e => Err(PacketError::UnsupportIPProtocol), } } @@ -765,6 +804,9 @@ mod tests { use crate::protocol::mpls::PWEthHeader; use crate::protocol::ppp::PPPHeader; use crate::protocol::ppp::PPPProtocol; + use crate::protocol::pppoe::PPPoECode; + use crate::protocol::pppoe::PPPoEHeader; + use crate::protocol::pppoe::PPPoEStage; use crate::protocol::pptp::PPTPControlMessageType; use crate::protocol::pptp::PPTPHeader; use crate::protocol::pptp::PPTPMessageType; @@ -3790,4 +3832,325 @@ mod tests { // assert_eq!(1, 0); } + + #[test] + fn test_packet_handle_eth_vlan_pppoes_ip_tcp() { + /* + * Frame 4: 1476 bytes on wire (11808 bits), 1476 bytes captured (11808 bits) + * Encapsulation type: Ethernet (1) + * Arrival Time: Jan 27, 2019 17:20:38.032759000 CST + * [Time shift for this packet: 0.000000000 seconds] + * Epoch Time: 1548580838.032759000 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: 4 + * Frame Length: 1476 bytes (11808 bits) + * Capture Length: 1476 bytes (11808 bits) + * [Frame is marked: False] + * [Frame is ignored: False] + * [Protocols in frame: eth:ethertype:vlan:ethertype:pppoes:ppp:ip:tcp] + * [Coloring Rule Name: TCP] + * [Coloring Rule String: tcp] + * Ethernet II, Src: 00:00:00_00:04:47 (00:00:00:00:04:47), Dst: 18:10:04:00:02:27 (18:10:04:00:02:27) + * Destination: 18:10:04:00:02:27 (18:10:04:00:02:27) + * Address: 18:10:04:00:02:27 (18:10:04:00:02:27) + * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default) + * .... ...0 .... .... .... .... = IG bit: Individual address (unicast) + * Source: 00:00:00_00:04:47 (00:00:00:00:04:47) + * Address: 00:00:00_00:04:47 (00:00:00:00:04:47) + * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default) + * .... ...0 .... .... .... .... = IG bit: Individual address (unicast) + * Type: 802.1Q Virtual LAN (0x8100) + * 802.1Q Virtual LAN, PRI: 3, DEI: 0, ID: 1476 + * 011. .... .... .... = Priority: Critical Applications (3) + * ...0 .... .... .... = DEI: Ineligible + * .... 0101 1100 0100 = ID: 1476 + * Type: PPPoE Session (0x8864) + * PPP-over-Ethernet Session + * 0001 .... = Version: 1 + * .... 0001 = Type: 1 + * Code: Session Data (0x00) + * Session ID: 0xb4bc + * Payload Length: 1452 + * Point-to-Point Protocol + * Protocol: Internet Protocol version 4 (0x0021) + * Internet Protocol Version 4, Src: 91.185.14.33, Dst: 100.65.55.0 + * 0100 .... = Version: 4 + * .... 0101 = Header Length: 20 bytes (5) + * Differentiated Services Field: 0x6c (DSCP: Unknown, ECN: Not-ECT) + * 0110 11.. = Differentiated Services Codepoint: Unknown (27) + * .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0) + * Total Length: 1450 + * Identification: 0x4aa7 (19111) + * 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: 92 + * Protocol: TCP (6) + * Header Checksum: 0xc91f [correct] + * [Header checksum status: Good] + * [Calculated Checksum: 0xc91f] + * Source Address: 91.185.14.33 + * Destination Address: 100.65.55.0 + * Transmission Control Protocol, Src Port: 443, Dst Port: 34532, Seq: 2797, Ack: 491, Len: 1398 + * Source Port: 443 + * Destination Port: 34532 + * [Stream index: 0] + * [Conversation completeness: Incomplete (12)] + * [TCP Segment Len: 1398] + * Sequence Number: 2797 (relative sequence number) + * Sequence Number (raw): 2083597842 + * [Next Sequence Number: 4195 (relative sequence number)] + * Acknowledgment Number: 491 (relative ack number) + * Acknowledgment number (raw): 3064322674 + * 1000 .... = Header Length: 32 bytes (8) + * Flags: 0x010 (ACK) + * 000. .... .... = Reserved: Not set + * ...0 .... .... = Accurate ECN: Not set + * .... 0... .... = Congestion Window Reduced: Not set + * .... .0.. .... = ECN-Echo: Not set + * .... ..0. .... = Urgent: Not set + * .... ...1 .... = Acknowledgment: Set + * .... .... 0... = Push: Not set + * .... .... .0.. = Reset: Not set + * .... .... ..0. = Syn: Not set + * .... .... ...0 = Fin: Not set + * [TCP Flags: ·······A····] + * Window: 160 + * [Calculated window size: 160] + * [Window size scaling factor: -1 (unknown)] + * Checksum: 0xfc48 [correct] + * [Checksum Status: Good] + * [Calculated Checksum: 0xfc48] + * Urgent Pointer: 0 + * Options: (12 bytes), No-Operation (NOP), No-Operation (NOP), Timestamps + * TCP Option - No-Operation (NOP) + * Kind: No-Operation (1) + * TCP Option - No-Operation (NOP) + * Kind: No-Operation (1) + * TCP Option - Timestamps + * Kind: Time Stamp Option (8) + * Length: 10 + * Timestamp value: 2623653805: TSval 2623653805, TSecr 7318490 + * Timestamp echo reply: 7318490 + * [Timestamps] + * [Time since first frame in this TCP stream: 0.000000000 seconds] + * [Time since previous frame in this TCP stream: 0.000000000 seconds] + * [SEQ/ACK analysis] + * [Bytes in flight: 4194] + * [Bytes sent since last PSH flag: 4194] + * TCP payload (1398 bytes) + * [Reassembled PDU in frame: 6] + * TCP segment data (1398 bytes) + */ + + let bytes = [ + 0x18, 0x10, 0x04, 0x00, 0x02, 0x27, 0x00, 0x00, 0x00, 0x00, 0x04, 0x47, 0x81, 0x00, + 0x65, 0xc4, 0x88, 0x64, 0x11, 0x00, 0xb4, 0xbc, 0x05, 0xac, 0x00, 0x21, 0x45, 0x6c, + 0x05, 0xaa, 0x4a, 0xa7, 0x40, 0x00, 0x5c, 0x06, 0xc9, 0x1f, 0x5b, 0xb9, 0x0e, 0x21, + 0x64, 0x41, 0x37, 0x00, 0x01, 0xbb, 0x86, 0xe4, 0x7c, 0x31, 0x2e, 0x12, 0xb6, 0xa5, + 0xda, 0x72, 0x80, 0x10, 0x00, 0xa0, 0xfc, 0x48, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, + 0x9c, 0x61, 0xc7, 0xad, 0x00, 0x6f, 0xab, 0xda, 0x82, 0xf5, 0xe8, 0x05, 0x48, 0x84, + 0x5d, 0xd9, 0x8e, 0x9c, 0x1f, 0xd7, 0x7b, 0x7e, 0xdd, 0x8a, 0x53, 0x1e, 0x40, 0xe6, + 0xeb, 0x1e, 0x42, 0x48, 0xc2, 0xd4, 0x9c, 0x22, 0xca, 0x6d, 0xb8, 0xc7, 0x34, 0x90, + 0x4b, 0xc4, 0x6d, 0x11, 0x5b, 0xdb, 0xe8, 0x01, 0x67, 0x98, 0xb6, 0xa7, 0x9d, 0xf6, + 0xac, 0xe6, 0x34, 0xac, 0xc5, 0x09, 0xf1, 0x2d, 0x82, 0x87, 0x0b, 0xcb, 0xc4, 0x66, + 0x85, 0x2f, 0x16, 0x69, 0x37, 0xde, 0xb1, 0x95, 0x44, 0xb3, 0xc9, 0xed, 0x22, 0xa9, + 0xa6, 0x5e, 0xdb, 0x48, 0x02, 0xec, 0x66, 0x44, 0x35, 0x3f, 0x84, 0x8c, 0x12, 0x8f, + 0x32, 0xf2, 0x75, 0xe3, 0xf0, 0xc6, 0x7d, 0x2b, 0x12, 0x2a, 0x95, 0x16, 0x0b, 0x71, + 0xc3, 0x52, 0xf7, 0x5c, 0xd4, 0xf6, 0x94, 0x4d, 0x6f, 0xeb, 0x48, 0x90, 0xc1, 0xac, + 0x53, 0x8c, 0xba, 0x5c, 0xc9, 0x56, 0x05, 0xf4, 0xc8, 0xf0, 0x96, 0xe9, 0x63, 0xf6, + 0x6b, 0x72, 0x99, 0x98, 0x1d, 0xb3, 0x5e, 0x55, 0x02, 0xca, 0xa0, 0x02, 0xde, 0x67, + 0xef, 0xa9, 0xfb, 0xa5, 0xa9, 0xd3, 0xfa, 0x8f, 0xbf, 0x3d, 0xf5, 0x9a, 0x6d, 0xc4, + 0x7e, 0x8f, 0xb1, 0x4a, 0xf7, 0x67, 0x33, 0x94, 0xd6, 0x79, 0x42, 0xd3, 0x4d, 0xd4, + 0x21, 0x89, 0x9a, 0xac, 0xa3, 0x48, 0x44, 0xe2, 0x3a, 0xc6, 0xc6, 0x3a, 0x2d, 0x44, + 0x46, 0x1b, 0x7f, 0x47, 0x4e, 0x11, 0x86, 0xdb, 0xcf, 0x81, 0x24, 0x63, 0xd3, 0x2c, + 0x28, 0x1f, 0x84, 0xa8, 0x4d, 0xe6, 0x3d, 0x91, 0xe1, 0x59, 0xc0, 0x1b, 0x16, 0x19, + 0xcf, 0x7a, 0x8b, 0xb6, 0x26, 0x9d, 0x3e, 0x2d, 0x78, 0x38, 0x49, 0xef, 0x4e, 0xa7, + 0x71, 0x46, 0x38, 0x80, 0xa4, 0xb7, 0xcc, 0x1b, 0xa9, 0xc2, 0x6e, 0xc4, 0xe0, 0x09, + 0x11, 0xff, 0xc2, 0x5f, 0xd0, 0x04, 0x47, 0x44, 0xe8, 0xf5, 0x1a, 0xd7, 0x45, 0xc4, + 0xe9, 0x18, 0xcc, 0x14, 0x9d, 0x7c, 0x84, 0x18, 0x9f, 0xed, 0xe4, 0x5e, 0xeb, 0x43, + 0xaf, 0x43, 0x83, 0x19, 0xe5, 0x70, 0x5b, 0x14, 0x60, 0x5d, 0x18, 0x90, 0xee, 0x83, + 0x6f, 0xdc, 0xbf, 0xdb, 0x74, 0x3d, 0xdf, 0x95, 0x43, 0x6a, 0xda, 0x5d, 0xcb, 0x0e, + 0x96, 0x35, 0xf8, 0xc9, 0xd3, 0x09, 0x46, 0xf5, 0xa2, 0x08, 0x3d, 0xfe, 0xc6, 0xf3, + 0x5e, 0x86, 0x6f, 0xdb, 0xb3, 0xbf, 0xf1, 0x50, 0x5b, 0x2d, 0x78, 0xb3, 0x0b, 0xb6, + 0x10, 0xad, 0x0e, 0x62, 0x00, 0x78, 0x7f, 0x49, 0x90, 0x5e, 0xeb, 0x40, 0xb8, 0xbf, + 0xa6, 0xb4, 0xb7, 0x92, 0x9c, 0x36, 0xd4, 0x5d, 0xcc, 0xd2, 0xc0, 0x0c, 0x9a, 0x03, + 0x87, 0xed, 0x09, 0x92, 0x33, 0x77, 0x1f, 0xed, 0xe1, 0xec, 0xfa, 0xd2, 0xc1, 0x86, + 0xc7, 0xd9, 0x98, 0xfe, 0x88, 0xd8, 0x8e, 0xa3, 0x95, 0x0a, 0xa3, 0x84, 0x45, 0x94, + 0xe6, 0xbe, 0x13, 0x06, 0xcb, 0x81, 0x38, 0x93, 0xac, 0x9b, 0xb9, 0x29, 0xa9, 0x06, + 0x5a, 0x71, 0xee, 0x60, 0x01, 0xed, 0x5f, 0xa2, 0x4c, 0x70, 0x8e, 0xe2, 0x02, 0x43, + 0x22, 0x40, 0xcd, 0xcb, 0xc4, 0x10, 0x0a, 0x27, 0x92, 0xf1, 0x74, 0xa2, 0x27, 0x52, + 0xbc, 0x84, 0x89, 0x5c, 0xdd, 0x0c, 0x43, 0x27, 0xdd, 0x07, 0x7a, 0x4d, 0xd4, 0x80, + 0x02, 0xd7, 0x4e, 0x80, 0x94, 0xfc, 0x8c, 0xba, 0x1a, 0xc8, 0x1b, 0xee, 0x12, 0x91, + 0x2c, 0x3e, 0x7f, 0xf3, 0xc8, 0xa3, 0x80, 0xfb, 0x60, 0x4f, 0x0e, 0x1c, 0x77, 0x1a, + 0x47, 0xfa, 0xfa, 0xe0, 0x6d, 0x0e, 0xf5, 0xca, 0x30, 0x57, 0x4b, 0xe0, 0x7b, 0xb8, + 0x68, 0xc3, 0xaa, 0xd3, 0x85, 0x6e, 0x2a, 0x35, 0xc6, 0xa2, 0xfd, 0xc6, 0x6d, 0x03, + 0xed, 0xf7, 0x4c, 0x17, 0xde, 0x82, 0x02, 0xa8, 0x8c, 0xd7, 0xd2, 0xbf, 0x87, 0xa9, + 0xc3, 0xc0, 0xb2, 0xc1, 0x28, 0x57, 0x08, 0x2b, 0x99, 0x4d, 0x2a, 0xfa, 0x7c, 0x0d, + 0xdc, 0xeb, 0x73, 0xbf, 0x0f, 0x04, 0xac, 0x18, 0xdb, 0x69, 0xf6, 0x44, 0x6d, 0x8a, + 0x88, 0x0d, 0x5f, 0x89, 0x29, 0x3e, 0xbc, 0x50, 0xfb, 0xf6, 0x3a, 0x08, 0x4b, 0x2c, + 0xb4, 0xe1, 0x90, 0xb2, 0xe8, 0x59, 0x21, 0x30, 0x1f, 0x1b, 0x44, 0x1b, 0x40, 0x11, + 0x88, 0x52, 0xeb, 0x16, 0xcc, 0x76, 0x54, 0x6a, 0x8e, 0x9a, 0x9b, 0x84, 0x5f, 0x1b, + 0x9a, 0x20, 0x95, 0x63, 0xbb, 0xbe, 0x06, 0xca, 0x2c, 0x50, 0x7e, 0x27, 0xff, 0x62, + 0x23, 0x3f, 0xca, 0x68, 0x78, 0x05, 0xbe, 0x20, 0x1d, 0x5e, 0x4b, 0x95, 0xe3, 0x22, + 0x84, 0x42, 0xa2, 0x2d, 0x8d, 0xe8, 0xb1, 0xf4, 0xf5, 0x16, 0x5e, 0x3b, 0xa1, 0xe9, + 0x3a, 0x19, 0xa2, 0xb1, 0x8d, 0x1b, 0xe2, 0x43, 0x9f, 0x65, 0x16, 0xb9, 0x37, 0x37, + 0x81, 0xe3, 0x95, 0x39, 0xfc, 0xd1, 0x5b, 0x0a, 0xff, 0xfe, 0x6d, 0x71, 0xa5, 0xd5, + 0xb0, 0x16, 0x10, 0x5f, 0x8f, 0xdd, 0xd8, 0xc6, 0x8e, 0xfb, 0xce, 0x84, 0xa0, 0xc8, + 0xad, 0xdb, 0x1d, 0xff, 0xcd, 0x79, 0xcf, 0x93, 0x28, 0xb8, 0xf6, 0x27, 0x2e, 0xb2, + 0xed, 0x57, 0xe6, 0xad, 0x6e, 0x0f, 0xeb, 0x30, 0xba, 0x42, 0xb6, 0x8b, 0x35, 0x3d, + 0x27, 0x04, 0x8e, 0xde, 0x36, 0x4d, 0xbf, 0x52, 0x08, 0x70, 0xee, 0x87, 0x74, 0xa8, + 0xc3, 0x3c, 0x14, 0x25, 0xf3, 0x80, 0x00, 0x25, 0x81, 0x8c, 0x89, 0xb9, 0xb2, 0x29, + 0x35, 0x62, 0x79, 0x50, 0x71, 0x10, 0xc7, 0x9e, 0x0f, 0x01, 0xdb, 0x73, 0x82, 0x35, + 0xe9, 0x49, 0x8a, 0x26, 0x98, 0xd5, 0xb7, 0xcd, 0x0c, 0xb2, 0x90, 0x78, 0x20, 0x04, + 0xed, 0x66, 0xe3, 0x37, 0x40, 0xcb, 0x8f, 0xc9, 0xbe, 0xa7, 0x8a, 0xf3, 0x62, 0x49, + 0x59, 0x1e, 0xb5, 0x4a, 0xdb, 0x3b, 0x73, 0x75, 0x7d, 0xbf, 0xb2, 0x29, 0xda, 0x30, + 0x02, 0x30, 0x11, 0x2e, 0xb4, 0x24, 0x76, 0xf2, 0x1d, 0x3a, 0x10, 0xce, 0x8a, 0x51, + 0xdd, 0x3b, 0xa1, 0x1b, 0x6e, 0x00, 0x4c, 0x5c, 0xd5, 0xbb, 0x13, 0xa5, 0x49, 0x5c, + 0x74, 0x25, 0x02, 0x36, 0x94, 0x37, 0xf2, 0xcf, 0xf1, 0x96, 0xf1, 0x02, 0xdf, 0x44, + 0xb5, 0x3c, 0x1c, 0xb3, 0xeb, 0x37, 0xc3, 0x89, 0x2a, 0x7f, 0x61, 0x64, 0x72, 0xcf, + 0x1e, 0x07, 0x2a, 0xa8, 0x62, 0xfb, 0xdb, 0x1d, 0x66, 0x4e, 0xe5, 0xe2, 0xd0, 0xdd, + 0xe7, 0xc1, 0xba, 0xcd, 0xc3, 0xd5, 0xcf, 0x40, 0x71, 0x04, 0x85, 0xcb, 0x00, 0x96, + 0xc4, 0x03, 0x0b, 0xa2, 0x05, 0xc8, 0x58, 0xc1, 0x75, 0x99, 0xba, 0x94, 0x5f, 0x1a, + 0x64, 0x91, 0x18, 0x15, 0x1f, 0xb2, 0xd9, 0xfa, 0x6d, 0xa5, 0x85, 0x38, 0x9d, 0xd8, + 0x80, 0x8f, 0x7b, 0x01, 0x0b, 0xf8, 0xd4, 0x87, 0xfe, 0xe0, 0x99, 0x7c, 0x80, 0x0f, + 0x2f, 0xbe, 0x0f, 0x01, 0x7a, 0xd2, 0x76, 0xea, 0xf0, 0x5a, 0x6a, 0x70, 0x09, 0x3f, + 0x16, 0x1a, 0xa3, 0x13, 0x61, 0xb9, 0xac, 0x3c, 0x75, 0xec, 0xa1, 0xd9, 0xa0, 0x67, + 0x3c, 0xa3, 0xfe, 0xf3, 0x04, 0x82, 0xa6, 0x96, 0x54, 0x7e, 0xd1, 0xf6, 0xe9, 0xf4, + 0xdc, 0x42, 0xdf, 0x42, 0x6e, 0xc9, 0x25, 0x81, 0xfd, 0x7f, 0x00, 0x3e, 0x5e, 0xce, + 0x0c, 0xc6, 0xff, 0xdb, 0x7e, 0x32, 0x92, 0x5f, 0xc8, 0x71, 0x83, 0x05, 0xf1, 0xa2, + 0x27, 0x60, 0x38, 0x68, 0xee, 0x85, 0x3c, 0x4e, 0xaa, 0x37, 0x95, 0xf4, 0x3c, 0x58, + 0x2f, 0xcd, 0xfb, 0xec, 0xbe, 0xe9, 0x09, 0xd1, 0xe6, 0x41, 0x24, 0x46, 0x2c, 0xe3, + 0x50, 0x7b, 0x21, 0x0a, 0x9a, 0xf9, 0x2c, 0xef, 0x13, 0xef, 0x84, 0x4e, 0x48, 0xb9, + 0x18, 0x3d, 0x29, 0x2f, 0x6b, 0x4a, 0x4d, 0x5c, 0x8c, 0x36, 0xe4, 0xb8, 0x42, 0xca, + 0xe8, 0xb9, 0xb5, 0xef, 0xe8, 0x5c, 0xb9, 0xe8, 0xbd, 0x81, 0x95, 0x21, 0x78, 0x08, + 0x67, 0xd0, 0x6a, 0x15, 0xfc, 0x24, 0x53, 0xfa, 0x5e, 0xcb, 0x06, 0xa7, 0x1d, 0x1a, + 0xd4, 0x61, 0xed, 0xfb, 0x41, 0x71, 0xe7, 0x12, 0x99, 0xb6, 0xc7, 0x03, 0x5f, 0x8b, + 0x6e, 0x66, 0xe5, 0xb3, 0xb0, 0xbd, 0x3d, 0x66, 0xb7, 0x0c, 0x19, 0x6a, 0x86, 0x99, + 0x47, 0x0a, 0x23, 0x11, 0xe9, 0x2c, 0xb4, 0x08, 0xf4, 0xd2, 0x26, 0xc5, 0x58, 0x70, + 0x84, 0x8a, 0xf9, 0xf1, 0x5a, 0x54, 0xce, 0x3b, 0x91, 0x36, 0x2c, 0x8b, 0x1f, 0xf0, + 0x3c, 0x2a, 0x48, 0x78, 0x5c, 0xcd, 0xa2, 0x64, 0x58, 0x61, 0x25, 0xdc, 0xda, 0xb9, + 0x67, 0x4c, 0xfd, 0x5c, 0xa3, 0x55, 0xbc, 0x5e, 0x6a, 0x69, 0xa1, 0xb7, 0x9e, 0xa9, + 0xa6, 0xcc, 0x7d, 0x3d, 0x41, 0xc2, 0xb3, 0x33, 0x63, 0x03, 0x4b, 0x45, 0x68, 0x6a, + 0x83, 0xad, 0xbc, 0x5c, 0xbb, 0x4c, 0xaf, 0xa9, 0xa5, 0x07, 0xc1, 0xa5, 0x5a, 0x28, + 0x06, 0xb9, 0xf6, 0x00, 0xa3, 0xca, 0xe9, 0x8d, 0x00, 0xa3, 0xdb, 0x17, 0x90, 0x6f, + 0x12, 0xd7, 0xd8, 0x17, 0x62, 0x09, 0xb3, 0xd3, 0x94, 0xec, 0x99, 0x52, 0x4c, 0x1a, + 0xa2, 0x1f, 0x17, 0x30, 0x26, 0x3d, 0x17, 0x9e, 0x09, 0xd1, 0x82, 0xcc, 0x3b, 0x7f, + 0x19, 0x0b, 0xa3, 0x2f, 0x97, 0x7b, 0x69, 0x9b, 0x44, 0x7b, 0x35, 0x83, 0xe8, 0x4c, + 0xfe, 0x66, 0xf0, 0xd1, 0x6a, 0x1c, 0xc6, 0x3d, 0xd0, 0xf2, 0xe1, 0xe5, 0x3a, 0x31, + 0x79, 0xeb, 0x02, 0xe4, 0x14, 0xa1, 0x70, 0x1d, 0x7f, 0x00, 0x6a, 0xe3, 0x74, 0xbe, + 0xc4, 0xea, 0x6e, 0xd7, 0xa1, 0xea, 0x0b, 0x4b, 0x2d, 0x8b, 0xab, 0x7f, 0x58, 0x4d, + 0xd9, 0xab, 0xd6, 0x96, 0x3f, 0x65, 0xff, 0x43, 0x14, 0x05, 0x31, 0xe4, 0x88, 0xfc, + 0x32, 0x13, 0xaf, 0x7c, 0x4f, 0x6b, 0x2b, 0x07, 0x5e, 0x60, 0xeb, 0x04, 0xcc, 0xaf, + 0x2e, 0x6e, 0x90, 0x80, 0xb4, 0xef, 0x01, 0xed, 0x63, 0xb2, 0x68, 0x99, 0x4b, 0x90, + 0xfa, 0xba, 0x8e, 0x74, 0x5b, 0x45, 0x80, 0x95, 0x6c, 0x67, 0xf7, 0xc9, 0x1d, 0xb7, + 0xa3, 0xe1, 0x5f, 0x4f, 0xcc, 0x1f, 0x1b, 0xeb, 0xe7, 0x2d, 0x99, 0xae, 0x8e, 0x84, + 0xd9, 0x56, 0xf5, 0x5b, 0xc8, 0xa0, 0x2e, 0x93, 0x3a, 0xb3, 0x26, 0x9c, 0xb2, 0xc8, + 0xb3, 0xbc, 0x8a, 0x56, 0xa0, 0x89, 0xf0, 0xe8, 0x44, 0xdd, 0x61, 0x54, 0x78, 0x20, + 0x6c, 0xd0, 0xf1, 0x56, 0xf9, 0x09, 0x7c, 0x75, 0x38, 0x7e, 0xf0, 0x97, 0x9c, 0xf6, + 0x3d, 0xa2, 0x49, 0x68, 0xe4, 0x08, 0x2f, 0x50, 0x32, 0xaf, 0x59, 0xbe, 0xb8, 0xa8, + 0x5c, 0x9e, 0x1b, 0xf8, 0x5f, 0xfe, + ]; + + 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::ETH( + EthHeader { + source_mac: MacAddress([0x00, 0x00, 0x00, 0x00, 0x04, 0x47]), + dest_mac: MacAddress([0x18, 0x10, 0x04, 0x00, 0x02, 0x27]), + ether_type: EthType::VLAN, + }, + &bytes[14..] + ) + ); + assert_eq!( + packet.encapsulation[1], + Encapsulation::VLAN( + VLANHeader { + priority_code_point: 3, + drop_eligible_indicator: false, + vlan_identifier: 1476, + ether_type: EthType::PPPoEsession + }, + &bytes[18..] + ) + ); + assert_eq!( + packet.encapsulation[2], + Encapsulation::PPPoE( + PPPoEHeader { + version: 1, + type_: 1, + code: PPPoECode::SessionData, + session_id: 0xb4bc, + payload_length: 1452, + stage: PPPoEStage::Session(PPPProtocol::IPv4) + }, + &bytes[26..] + ) + ); + assert_eq!( + packet.encapsulation[3], + Encapsulation::IPv4( + IPv4Header { + version: 4, + ihl: 20, + tos: 108, + length: 1450, + id: 19111, + flags: 0x2, + frag_offset: 0, + ttl: 92, + protocol: IPProtocol::TCP, + checksum: 0xc91f, + source_address: Ipv4Addr::new(91, 185, 14, 33), + dest_address: Ipv4Addr::new(100, 65, 55, 0) + }, + &bytes[46..] + ) + ); + assert_eq!( + packet.encapsulation[4], + Encapsulation::TCP( + TCPHeader { + source_port: 443, + dest_port: 34532, + seq_num: 2083597842, + ack_num: 3064322674, + data_offset: 32, + reserved: 0, + flag_urg: false, + flag_ack: true, + flag_psh: false, + flag_rst: false, + flag_syn: false, + flag_fin: false, + window: 160, + checksum: 0xfc48, + urgent_ptr: 0, + options: Some(vec![ + TCPOption::NOP, + TCPOption::NOP, + TCPOption::TIMESTAMPS { + length: 10, + ts_value: 2623653805, + ts_reply: 7318490 + } + ]) + }, + &bytes[78..] + ) + ) + + // assert_eq!(1, 0); + } } diff --git a/src/protocol/ethernet.rs b/src/protocol/ethernet.rs index d3b9fc0..396dc22 100644 --- a/src/protocol/ethernet.rs +++ b/src/protocol/ethernet.rs @@ -203,11 +203,16 @@ mod tests { assert_eq!(EthHeader::decode(&bytes), Ok((LAST_SLICE, expectation))); // example - let ethernet = EthHeader::decode(&bytes); - if let Ok((payload, header)) = ethernet { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + let result = EthHeader::decode(&bytes); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } } diff --git a/src/protocol/grev0.rs b/src/protocol/grev0.rs index 8ef5a20..88a43f1 100644 --- a/src/protocol/grev0.rs +++ b/src/protocol/grev0.rs @@ -238,11 +238,16 @@ mod tests { // example let result = GREv0Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } #[test] @@ -325,10 +330,15 @@ mod tests { // example let result = GREv0Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } } diff --git a/src/protocol/grev1.rs b/src/protocol/grev1.rs index a16bab6..ed2d2f2 100644 --- a/src/protocol/grev1.rs +++ b/src/protocol/grev1.rs @@ -177,10 +177,15 @@ mod tests { // example let result = GREv1Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } } diff --git a/src/protocol/gtpv1.rs b/src/protocol/gtpv1.rs index 9acfc0f..bc01b41 100644 --- a/src/protocol/gtpv1.rs +++ b/src/protocol/gtpv1.rs @@ -206,10 +206,13 @@ mod tests { // example let result = GTPv1Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -272,10 +275,13 @@ mod tests { // example let result = GTPv1Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); diff --git a/src/protocol/icmp.rs b/src/protocol/icmp.rs index fee8749..991a191 100644 --- a/src/protocol/icmp.rs +++ b/src/protocol/icmp.rs @@ -136,10 +136,13 @@ mod tests { // example let result = ICMPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); diff --git a/src/protocol/icmpv6.rs b/src/protocol/icmpv6.rs index 26728f4..9bd58d2 100644 --- a/src/protocol/icmpv6.rs +++ b/src/protocol/icmpv6.rs @@ -170,10 +170,13 @@ mod tests { // example let result = ICMPv6Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); diff --git a/src/protocol/ipv4.rs b/src/protocol/ipv4.rs index 61dce29..7606b1e 100644 --- a/src/protocol/ipv4.rs +++ b/src/protocol/ipv4.rs @@ -179,10 +179,15 @@ mod tests { // example let result = IPv4Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } } diff --git a/src/protocol/ipv6.rs b/src/protocol/ipv6.rs index 639c023..8ee78c3 100644 --- a/src/protocol/ipv6.rs +++ b/src/protocol/ipv6.rs @@ -231,11 +231,16 @@ mod tests { // example let result = IPv6Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } #[test] @@ -305,10 +310,13 @@ mod tests { // example let result = IPv6Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -378,10 +386,13 @@ mod tests { // example let result = IPv6Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -500,10 +511,13 @@ mod tests { // example let result = IPv6Header::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); diff --git a/src/protocol/l2tp.rs b/src/protocol/l2tp.rs index ebed837..90c5ea5 100644 --- a/src/protocol/l2tp.rs +++ b/src/protocol/l2tp.rs @@ -464,10 +464,13 @@ mod tests { // example let result = L2TPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -513,10 +516,13 @@ mod tests { // example let result = L2TPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -565,10 +571,13 @@ mod tests { // example let result = L2TPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -776,10 +785,13 @@ mod tests { // example let result = L2TPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 16b9963..db1b38c 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -16,4 +16,5 @@ pub mod l2tp; pub mod grev0; pub mod grev1; pub mod pptp; -pub mod ppp; \ No newline at end of file +pub mod ppp; +pub mod pppoe; \ No newline at end of file diff --git a/src/protocol/ppp.rs b/src/protocol/ppp.rs index 558e9a6..97fa0e5 100644 --- a/src/protocol/ppp.rs +++ b/src/protocol/ppp.rs @@ -106,10 +106,15 @@ mod tests { // example let result = PPPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } } diff --git a/src/protocol/pppoe.rs b/src/protocol/pppoe.rs new file mode 100644 index 0000000..fbd8448 --- /dev/null +++ b/src/protocol/pppoe.rs @@ -0,0 +1,252 @@ +use crate::protocol::codec::Decode; +use crate::protocol::ppp::PPPProtocol; +use nom::bits; +use nom::error::Error; +use nom::number; +use nom::sequence; +use nom::IResult; + +/****************************************************************************** + * Struct + ******************************************************************************/ + +/* + * RFC 2516 - A Method for Transmitting PPP Over Ethernet (PPPoE) + * + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | VER | TYPE | CODE | SESSION_ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | LENGTH | payload ~ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * https://datatracker.ietf.org/doc/html/rfc2516 + * https://info.support.huawei.com/info-finder/encyclopedia/zh/PPPoE.html + */ + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum PPPoECode { + SessionData, // Session Data + PADI, // Active Discovery Initiation + PADO, // Active Discovery Offer + PADR, // Active Discovery Request + PADS, // Active Discovery Session-confirmation + PADT, // Active Discovery Terminate + Other(u8), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum PPPoETagType { + EndOfList, + ServiceName, + ACName, + HostUniq, + ACcookie, + VendorSpecific, + RelaySessionId, + ServiceNameError, + ACSystemError, + GenericError, + Other(u16), +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct PPPoETag { + pub tag_type: PPPoETagType, + pub tag_length: u16, + pub tag_value: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum PPPoEStage { + Discovery(Vec), + Session(PPPProtocol), +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct PPPoEHeader { + pub version: u8, // 4 bits + pub type_: u8, // 4 bits + pub code: PPPoECode, // 8 bits + pub session_id: u16, // 16 bits + pub payload_length: u16, // 16 bits + pub stage: PPPoEStage, +} + +/****************************************************************************** + * API + ******************************************************************************/ + +impl From for PPPoECode { + fn from(raw: u8) -> Self { + match raw { + 0x00 => PPPoECode::SessionData, + 0x09 => PPPoECode::PADI, + 0x07 => PPPoECode::PADO, + 0x19 => PPPoECode::PADR, + 0x65 => PPPoECode::PADS, + 0xa7 => PPPoECode::PADT, + other => PPPoECode::Other(other), + } + } +} + +impl From for PPPoETagType { + fn from(raw: u16) -> Self { + match raw { + 0x0000 => PPPoETagType::EndOfList, + 0x0101 => PPPoETagType::ServiceName, + 0x0102 => PPPoETagType::ACName, + 0x0103 => PPPoETagType::HostUniq, + 0x0104 => PPPoETagType::ACcookie, + 0x0105 => PPPoETagType::VendorSpecific, + 0x0110 => PPPoETagType::RelaySessionId, + 0x0201 => PPPoETagType::ServiceNameError, + 0x0202 => PPPoETagType::ACSystemError, + 0x0203 => PPPoETagType::GenericError, + other => PPPoETagType::Other(other), + } + } +} + +fn version_type_decode(input: &[u8]) -> IResult<&[u8], (u8, u8)> { + bits::bits::<_, _, Error<_>, _, _>(sequence::tuple(( + bits::streaming::take(4u8), + bits::streaming::take(4u8), + )))(input) +} + +fn pppoe_tag_decode(input: &[u8]) -> IResult<&[u8], PPPoETag> { + let (input, tag_type) = number::complete::be_u16(input)?; + let (input, tag_length) = number::complete::be_u16(input)?; + let (input, tag_value) = nom::bytes::complete::take(tag_length)(input)?; + Ok(( + input, + PPPoETag { + tag_type: tag_type.into(), + tag_length, + tag_value: tag_value.to_vec(), + }, + )) +} + +fn pppoe_tags_decode(input: &[u8]) -> IResult<&[u8], Vec> { + let mut tags = Vec::new(); + let mut remain = input; + loop { + let (input, tag) = pppoe_tag_decode(remain)?; + let tag_type = tag.tag_type; + remain = input; + tags.push(tag); + if remain.is_empty() || tag_type == PPPoETagType::EndOfList { + break; + } + } + Ok((remain, tags)) +} + +impl Decode for PPPoEHeader { + type Iterm = PPPoEHeader; + fn decode(input: &[u8]) -> IResult<&[u8], PPPoEHeader> { + let (input, (version, type_)) = version_type_decode(input)?; + /* + * https://datatracker.ietf.org/doc/html/rfc2516 + * + * The VER field is four bits and MUST be set to 0x1 for this version of the PPPoE specification. + * The TYPE field is four bits and MUST be set to 0x1 for this version of the PPPoE specification. + */ + match (version, type_) { + (0x1, 0x1) => {} + _ => { + return Err(nom::Err::Error(Error::new( + input, + nom::error::ErrorKind::Verify, + ))) + } + } + let (input, code) = number::complete::be_u8(input)?; + let (input, session_id) = number::complete::be_u16(input)?; + let (input, payload_length) = number::complete::be_u16(input)?; + let (input, stage) = match code.into() { + PPPoECode::SessionData => { + let (input, ppp_protocol) = PPPProtocol::decode(input)?; + (input, PPPoEStage::Session(ppp_protocol)) + } + _ => { + let (remain, tags) = pppoe_tags_decode(input)?; + (remain, PPPoEStage::Discovery(tags)) + } + }; + + Ok(( + input, + PPPoEHeader { + version, + type_, + code: code.into(), + session_id, + payload_length, + stage, + }, + )) + } +} + +/****************************************************************************** + * TEST + ******************************************************************************/ + +#[cfg(test)] +mod tests { + use super::PPPoECode; + use super::PPPoEHeader; + use super::PPPoEStage; + use crate::protocol::codec::Decode; + use crate::protocol::ppp::PPPProtocol; + const LAST_SLICE: &'static [u8] = &[0xff]; + + #[test] + fn pppoe_header_decode() { + /* + * PPP-over-Ethernet Session + * 0001 .... = Version: 1 + * .... 0001 = Type: 1 + * Code: Session Data (0x00) + * Session ID: 0xb4bc + * Payload Length: 544 + * Point-to-Point Protocol + * Protocol: Internet Protocol version 4 (0x0021) + */ + + let bytes = [ + 0x11, 0x00, 0xb4, 0xbc, 0x02, 0x20, /* PPPoE */ + 0x00, 0x21, /* PPP */ + 0xff, /* Payload */ + ]; + + let expectation = PPPoEHeader { + version: 1, + type_: 1, + code: PPPoECode::SessionData, + session_id: 0xb4bc, + payload_length: 544, + stage: PPPoEStage::Session(PPPProtocol::IPv4), + }; + + assert_eq!(PPPoEHeader::decode(&bytes), Ok((LAST_SLICE, expectation))); + + // example + let result = PPPoEHeader::decode(&bytes); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } + } + + // assert_eq!(1, 0); + } +} diff --git a/src/protocol/pptp.rs b/src/protocol/pptp.rs index ce8bd58..ed64a26 100644 --- a/src/protocol/pptp.rs +++ b/src/protocol/pptp.rs @@ -204,10 +204,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -274,10 +277,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -316,10 +322,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -358,10 +367,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -398,10 +410,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -441,10 +456,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -516,10 +534,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -568,10 +589,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -639,10 +663,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -704,10 +731,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); @@ -759,10 +789,13 @@ mod tests { // example let result = PPTPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } // assert_eq!(1, 0); diff --git a/src/protocol/udp.rs b/src/protocol/udp.rs index 625c9e9..1d7b43b 100644 --- a/src/protocol/udp.rs +++ b/src/protocol/udp.rs @@ -100,10 +100,15 @@ mod tests { // example let result = UDPHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } } diff --git a/src/protocol/vlan.rs b/src/protocol/vlan.rs index 17a82e1..6a1dbe0 100644 --- a/src/protocol/vlan.rs +++ b/src/protocol/vlan.rs @@ -84,10 +84,15 @@ mod tests { // example let result = VLANHeader::decode(&bytes); - if let Ok((payload, header)) = result { - println!("return: {:?}, payload: {}", header, payload.len()); - } else { - println!("return: Incomplete data"); + match result { + Ok((payload, header)) => { + println!("OK: {:?}, payload: {}", header, payload.len()); + } + Err(e) => { + println!("ERR: {:?}", e); + } } + + // assert_eq!(1, 0); } } -- cgit v1.2.3