summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs6
-rw-r--r--src/packet/error.rs4
-rw-r--r--src/packet/packet.rs46
-rw-r--r--src/protocol/icmp.rs147
-rw-r--r--src/protocol/mod.rs3
5 files changed, 197 insertions, 9 deletions
diff --git a/src/main.rs b/src/main.rs
index c1286bd..d4fc3ac 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -22,6 +22,9 @@ fn trigger_packet_event(
PacketEvent::L2_EVENT => {
BuiltInEvent::trigger_l2_event(event_mgr.clone(), session.clone());
}
+ PacketEvent::L2_VLAN => {
+ // TODO
+ }
PacketEvent::L3_EVENT => {
BuiltInEvent::trigger_l3_event(event_mgr.clone(), session.clone());
}
@@ -40,6 +43,9 @@ fn trigger_packet_event(
PacketEvent::UDP_EVENT => {
BuiltInEvent::trigger_udp_event(event_mgr.clone(), session.clone());
}
+ PacketEvent::ICMP_EVENT => {
+ // TODO
+ }
}
}
}
diff --git a/src/packet/error.rs b/src/packet/error.rs
index 174930c..55523be 100644
--- a/src/packet/error.rs
+++ b/src/packet/error.rs
@@ -4,6 +4,7 @@ pub enum PacketError {
// L2
IncompleteEthernetFrame,
+ IncompleteVlanHeader,
UnsupportEthernetType,
// L3
@@ -18,6 +19,7 @@ pub enum PacketError {
// L4
IncompleteUdpHeader,
IncompleteTcpHeader,
+ IncompleteIcmpHeader,
}
impl core::fmt::Display for PacketError {
@@ -26,6 +28,7 @@ impl core::fmt::Display for PacketError {
PacketError::InvalidPacketLength => write!(f, "Invalid Packet Length"),
// L2
PacketError::IncompleteEthernetFrame => write!(f, "Incomplete Ethernet Frame"),
+ PacketError::IncompleteVlanHeader => write!(f, "Incomplete VLAN Header"),
PacketError::UnsupportEthernetType => write!(f, "Unsupport Ethernet Type"),
// L3
PacketError::IncompleteIpv4Header => write!(f, "Incomplete IPv4 Header"),
@@ -36,6 +39,7 @@ impl core::fmt::Display for PacketError {
// L4
PacketError::IncompleteUdpHeader => write!(f, "Incomplete UDP Header"),
PacketError::IncompleteTcpHeader => write!(f, "Incomplete TCP Header"),
+ PacketError::IncompleteIcmpHeader => write!(f, "Incomplete ICMP Header"),
}
}
}
diff --git a/src/packet/packet.rs b/src/packet/packet.rs
index 23bbc6f..7e1c8ef 100644
--- a/src/packet/packet.rs
+++ b/src/packet/packet.rs
@@ -2,6 +2,7 @@ use crate::packet::error::PacketError;
use crate::protocol::codec::Decode;
use crate::protocol::ethernet::EtherType;
use crate::protocol::ethernet::EthernetFrame;
+use crate::protocol::icmp::IcmpHeader;
use crate::protocol::ip::IPProtocol;
use crate::protocol::ipv4::IPv4Header;
use crate::protocol::ipv6::IPv6Header;
@@ -13,13 +14,14 @@ use crate::protocol::vlan::VlanHeader;
#[derive(Clone, Debug, PartialEq)]
pub enum Encapsulation<'a> {
L2_ETH(EthernetFrame, &'a [u8]),
+ L2_VLAN(VlanHeader, &'a [u8]),
- L3_VLAN(VlanHeader, &'a [u8]),
L3_IPV4(IPv4Header, &'a [u8]),
L3_IPV6(IPv6Header, &'a [u8]),
L4_TCP(TcpHeader, &'a [u8]),
L4_UDP(UdpHeader, &'a [u8]),
+ L4_ICMP(IcmpHeader, &'a [u8]),
UNSUPPORTED(&'a [u8]),
}
@@ -27,13 +29,20 @@ pub enum Encapsulation<'a> {
#[allow(non_camel_case_types)]
#[derive(Clone, Debug, PartialEq)]
pub enum PacketEvent {
+ // L2 Layer Event
L2_EVENT,
+ L2_VLAN,
+
+ // L3 Layer Event
L3_EVENT,
IPV4_EVENT,
IPV6_EVENT,
+
+ // L4 Layer Event
L4_EVENT,
TCP_EVENT,
UDP_EVENT,
+ ICMP_EVENT,
}
#[derive(Debug)]
@@ -356,9 +365,11 @@ fn handle_l2<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketE
let result = EthernetFrame::decode(input);
if let Ok((payload, header)) = result {
dbg!(&header);
+
packet
.encapsulation
.push(Encapsulation::L2_ETH(header, payload));
+
packet.event.push(PacketEvent::L2_EVENT);
return handle_l3(packet, payload, header.ether_type);
} else {
@@ -379,11 +390,13 @@ fn handle_l3<'a>(
packet
.encapsulation
- .push(Encapsulation::L3_VLAN(header, payload));
- packet.event.push(PacketEvent::L3_EVENT);
+ .push(Encapsulation::L2_VLAN(header, payload));
+
+ packet.event.push(PacketEvent::L2_EVENT);
+ packet.event.push(PacketEvent::L2_VLAN);
return handle_l3(packet, payload, header.ether_type);
} else {
- return Err(PacketError::IncompleteEthernetFrame);
+ return Err(PacketError::IncompleteVlanHeader);
}
}
EtherType::IPv4 => {
@@ -442,10 +455,27 @@ fn handle_l4<'a>(
next_proto: IPProtocol,
) -> Result<(), PacketError> {
match next_proto {
+ IPProtocol::ICMP => {
+ let result = IcmpHeader::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+
+ packet
+ .encapsulation
+ .push(Encapsulation::L4_ICMP(header, payload));
+
+ packet.event.push(PacketEvent::L4_EVENT);
+ packet.event.push(PacketEvent::ICMP_EVENT);
+ return Ok(());
+ } else {
+ return Err(PacketError::IncompleteIcmpHeader);
+ }
+ }
IPProtocol::UDP => {
let result = UdpHeader::decode(input);
if let Ok((payload, header)) = result {
dbg!(&header);
+
packet
.encapsulation
.push(Encapsulation::L4_UDP(header, payload));
@@ -757,7 +787,7 @@ mod tests {
);
assert_eq!(
packet.encapsulation[1],
- Encapsulation::L3_VLAN(
+ Encapsulation::L2_VLAN(
VlanHeader {
priority_code_point: 0,
drop_eligible_indicator: false,
@@ -769,7 +799,7 @@ mod tests {
);
assert_eq!(
packet.encapsulation[2],
- Encapsulation::L3_VLAN(
+ Encapsulation::L2_VLAN(
VlanHeader {
priority_code_point: 0,
drop_eligible_indicator: false,
@@ -956,7 +986,7 @@ mod tests {
);
assert_eq!(
packet.encapsulation[1],
- Encapsulation::L3_VLAN(
+ Encapsulation::L2_VLAN(
VlanHeader {
priority_code_point: 0,
drop_eligible_indicator: false,
@@ -968,7 +998,7 @@ mod tests {
);
assert_eq!(
packet.encapsulation[2],
- Encapsulation::L3_VLAN(
+ Encapsulation::L2_VLAN(
VlanHeader {
priority_code_point: 0,
drop_eligible_indicator: false,
diff --git a/src/protocol/icmp.rs b/src/protocol/icmp.rs
new file mode 100644
index 0000000..c1352d5
--- /dev/null
+++ b/src/protocol/icmp.rs
@@ -0,0 +1,147 @@
+use crate::protocol::codec::Decode;
+use nom::number;
+use nom::IResult;
+
+/******************************************************************************
+ * Struct
+ ******************************************************************************/
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum IcmpType {
+ EchoReply,
+ DestinationUnreachable,
+ SourceQuench,
+ Redirect,
+ EchoRequest,
+ RouterAdvertisement,
+ RouterSolicitation,
+ TimeExceeded,
+ ParameterProblem,
+ Timestamp,
+ TimestampReply,
+ InformationRequest,
+ InformationReply,
+ AddressMaskRequest,
+ AddressMaskReply,
+ Traceroute,
+ Other(u8),
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct IcmpHeader {
+ pub icmp_type: IcmpType,
+ pub icmp_code: u8,
+ pub icmp_checksum: u16,
+ pub icmp_payload: Vec<u8>,
+}
+
+/******************************************************************************
+ * API
+ ******************************************************************************/
+
+impl From<u8> for IcmpType {
+ fn from(raw: u8) -> Self {
+ match raw {
+ 0 => IcmpType::EchoReply,
+ 3 => IcmpType::DestinationUnreachable,
+ 4 => IcmpType::SourceQuench,
+ 5 => IcmpType::Redirect,
+ 8 => IcmpType::EchoRequest,
+ 9 => IcmpType::RouterAdvertisement,
+ 10 => IcmpType::RouterSolicitation,
+ 11 => IcmpType::TimeExceeded,
+ 12 => IcmpType::ParameterProblem,
+ 13 => IcmpType::Timestamp,
+ 14 => IcmpType::TimestampReply,
+ 15 => IcmpType::InformationRequest,
+ 16 => IcmpType::InformationReply,
+ 17 => IcmpType::AddressMaskRequest,
+ 18 => IcmpType::AddressMaskReply,
+ 30 => IcmpType::Traceroute,
+ other => IcmpType::Other(other),
+ }
+ }
+}
+
+impl Decode for IcmpHeader {
+ type Iterm = IcmpHeader;
+ fn decode(input: &[u8]) -> IResult<&[u8], IcmpHeader> {
+ let (input, icmp_type) = number::streaming::be_u8(input)?;
+ let (input, icmp_code) = number::streaming::be_u8(input)?;
+ let (input, icmp_checksum) = number::streaming::be_u16(input)?;
+ let (input, icmp_payload) = nom::bytes::streaming::take(4u8)(input)?;
+
+ Ok((
+ input,
+ IcmpHeader {
+ icmp_type: icmp_type.into(),
+ icmp_code,
+ icmp_checksum,
+ icmp_payload: icmp_payload.to_vec(),
+ },
+ ))
+ }
+}
+
+/******************************************************************************
+ * TEST
+ ******************************************************************************/
+
+#[cfg(test)]
+mod tests {
+ use super::IcmpHeader;
+ use crate::protocol::{codec::Decode, icmp::IcmpType};
+ const LAST_SLICE: &'static [u8] = &[
+ 0x96, 0xb5, 0xe9, 0x5e, 0x00, 0x00, 0x00, 0x00, 0xac, 0xe6, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 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,
+ ];
+
+ #[test]
+ fn icmp_header_decode() {
+ /*
+ * Internet Control Message Protocol
+ * Type: 8 (Echo (ping) request)
+ * Code: 0
+ * Checksum: 0xab05 [correct]
+ * [Checksum Status: Good]
+ * Identifier (BE): 24363 (0x5f2b)
+ * Identifier (LE): 11103 (0x2b5f)
+ * Sequence Number (BE): 1 (0x0001)
+ * Sequence Number (LE): 256 (0x0100)
+ * [Response frame: 2]
+ * Timestamp from icmp data: Jun 17, 2020 14:17:58.000000000 CST
+ * [Timestamp from icmp data (relative): 0.055548000 seconds]
+ * Data (48 bytes)
+ * Data: ace6020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b…
+ * [Length: 48]
+ */
+ let bytes = [
+ 0x08, 0x00, 0xab, 0x05, 0x5f, 0x2b, 0x00, 0x01, /* Payload */
+ 0x96, 0xb5, 0xe9, 0x5e, 0x00, 0x00, 0x00, 0x00, 0xac, 0xe6, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 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,
+ ];
+
+ let expectation = IcmpHeader {
+ icmp_type: IcmpType::EchoRequest,
+ icmp_code: 0,
+ icmp_checksum: 0xab05,
+ icmp_payload: vec![0x5f, 0x2b, 0x00, 0x01],
+ };
+
+ assert_eq!(IcmpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let vlan = IcmpHeader::decode(&bytes);
+ if let Ok((payload, header)) = vlan {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+}
diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs
index 044481a..ba06b66 100644
--- a/src/protocol/mod.rs
+++ b/src/protocol/mod.rs
@@ -7,4 +7,5 @@ pub mod udp;
pub mod tcp;
pub mod dns;
pub mod http;
-pub mod vlan; \ No newline at end of file
+pub mod vlan;
+pub mod icmp; \ No newline at end of file