summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs3
-rw-r--r--src/packet/mod.rs1
-rw-r--r--src/packet/packet.rs407
-rw-r--r--src/protocol/http.rs20
-rw-r--r--src/protocol/ipv4.rs2
-rw-r--r--src/protocol/ipv6.rs2
-rw-r--r--src/protocol/mod.rs3
7 files changed, 436 insertions, 2 deletions
diff --git a/src/lib.rs b/src/lib.rs
index c8b4a9f..c9cf115 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1 +1,2 @@
-pub mod protocol; \ No newline at end of file
+pub mod packet;
+pub mod protocol;
diff --git a/src/packet/mod.rs b/src/packet/mod.rs
new file mode 100644
index 0000000..edb43db
--- /dev/null
+++ b/src/packet/mod.rs
@@ -0,0 +1 @@
+pub mod packet;
diff --git a/src/packet/packet.rs b/src/packet/packet.rs
new file mode 100644
index 0000000..c199d8d
--- /dev/null
+++ b/src/packet/packet.rs
@@ -0,0 +1,407 @@
+use crate::protocol::dns::DNS_MESSAGE;
+use crate::protocol::ethernet::EtherType;
+use crate::protocol::ethernet::EthernetFrame;
+use crate::protocol::http::HTTP_MESSAGE;
+use crate::protocol::ip::IPProtocol;
+use crate::protocol::ipv4::IPv4Header;
+use crate::protocol::ipv6::IPv6Header;
+use crate::protocol::tcp::TcpHeader;
+use crate::protocol::udp::UdpHeader;
+
+use core::fmt::Error;
+
+#[allow(non_camel_case_types)]
+#[derive(Clone, Debug)]
+pub enum Encapsulation<'a> {
+ L2_ETH(EthernetFrame, &'a [u8]),
+
+ L3_IP4(IPv4Header, &'a [u8]),
+ L3_IP6(IPv6Header, &'a [u8]),
+
+ L4_TCP(TcpHeader, &'a [u8]),
+ L4_UDP(UdpHeader, &'a [u8]),
+
+ L7_DNS(DNS_MESSAGE, &'a [u8]),
+ L7_HTTP(HTTP_MESSAGE, &'a [u8]),
+
+ Unsupported(&'a [u8]),
+}
+
+#[derive(Debug)]
+pub struct Packet<'a> {
+ pub orig_data: &'a [u8],
+ pub orig_len: u32,
+ pub encapsulation: Vec<Encapsulation<'a>>,
+}
+
+impl Packet<'_> {
+ pub fn new(data: &[u8], len: u32) -> Packet {
+ Packet {
+ orig_data: data,
+ orig_len: len,
+ encapsulation: vec![],
+ }
+ }
+
+ pub fn handle(&mut self) -> Result<(), Error> {
+ return handle_l2(self, self.orig_data);
+ }
+}
+
+fn handle_l2<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Error> {
+ let result = EthernetFrame::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+ packet
+ .encapsulation
+ .push(Encapsulation::L2_ETH(header, payload));
+ return handle_l3(packet, payload, header.ether_type);
+ }
+
+ println!("handle_l2: Incomplete data {:?}", input);
+ return Ok(());
+}
+
+fn handle_l3<'a>(
+ packet: &mut Packet<'a>,
+ input: &'a [u8],
+ next_proto: EtherType,
+) -> Result<(), Error> {
+ match next_proto {
+ EtherType::IPv4 => {
+ let result = IPv4Header::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+ packet
+ .encapsulation
+ .push(Encapsulation::L3_IP4(header, payload));
+ // TODO IPv4 Fragment
+ return handle_l4(packet, payload, header.protocol);
+ }
+ }
+ EtherType::IPv6 => {
+ let result = IPv6Header::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+ packet
+ .encapsulation
+ .push(Encapsulation::L3_IP6(header, payload));
+ // TODO IPv6 Fragment
+ return handle_l4(packet, payload, header.next_header);
+ }
+ }
+ e => {
+ println!("handle_l3: Unsupported EtherType {:?}", e);
+ return Ok(());
+ }
+ }
+
+ println!("handle_l3: Incomplete data {:?}", input);
+ return Ok(());
+}
+
+fn handle_l4<'a>(
+ packet: &mut Packet<'a>,
+ input: &'a [u8],
+ next_proto: IPProtocol,
+) -> Result<(), Error> {
+ match next_proto {
+ IPProtocol::UDP => {
+ let result = UdpHeader::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+ packet
+ .encapsulation
+ .push(Encapsulation::L4_UDP(header, payload));
+ return handle_l7(packet, payload);
+ }
+ }
+ IPProtocol::TCP => {
+ let result = TcpHeader::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+ packet
+ .encapsulation
+ .push(Encapsulation::L4_TCP(header, payload));
+ // TODO TCP Reassembly
+ return handle_l7(packet, payload);
+ }
+ }
+ e => {
+ println!("handle_l4: Unsupported IPProtocol {:?}", e);
+ return Ok(());
+ }
+ }
+
+ println!("handle_l4: Incomplete data {:?}", input);
+ return Ok(());
+}
+
+fn handle_l7<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Error> {
+ let result = DNS_MESSAGE::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+ packet
+ .encapsulation
+ .push(Encapsulation::L7_DNS(header, payload));
+ return Ok(());
+ }
+
+ let result = HTTP_MESSAGE::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+ packet
+ .encapsulation
+ .push(Encapsulation::L7_HTTP(header, payload));
+ return Ok(());
+ }
+
+ println!("handle_l7: Incomplete data {:?}", input);
+ return Ok(());
+}
+
+/******************************************************************************
+ * TEST
+ ******************************************************************************/
+
+#[cfg(test)]
+mod tests {
+ use super::Packet;
+
+ #[test]
+ fn test_packet_handle1() {
+ /*
+ * Frame 49: 74 bytes on wire (592 bits), 74 bytes captured (592 bits) on interface en0, id 0
+ * Section number: 1
+ * Interface id: 0 (en0)
+ * Interface name: en0
+ * Interface description: Wi-Fi
+ * Encapsulation type: Ethernet (1)
+ * Arrival Time: Aug 2, 2023 11:36:35.739393000 CST
+ * [Time shift for this packet: 0.000000000 seconds]
+ * Epoch Time: 1690947395.739393000 seconds
+ * [Time delta from previous captured frame: 0.496904000 seconds]
+ * [Time delta from previous displayed frame: 0.000000000 seconds]
+ * [Time since reference or first frame: 7.146758000 seconds]
+ * Frame Number: 49
+ * Frame Length: 74 bytes (592 bits)
+ * Capture Length: 74 bytes (592 bits)
+ * [Frame is marked: False]
+ * [Frame is ignored: False]
+ * [Protocols in frame: eth:ethertype:ip:udp:dns]
+ * [Coloring Rule Name: UDP]
+ * [Coloring Rule String: udp]
+ * Ethernet II, Src: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea), Dst: NewH3CTe_96:38:0e (48:73:97:96:38:0e)
+ * Destination: NewH3CTe_96:38:0e (48:73:97:96:38:0e)
+ * Address: NewH3CTe_96:38:0e (48:73:97:96:38:0e)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Source: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea)
+ * Address: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Type: IPv4 (0x0800)
+ * Internet Protocol Version 4, Src: 192.168.38.63, Dst: 192.168.44.40
+ * 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: 60
+ * Identification: 0x040c (1036)
+ * 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: 64
+ * Protocol: UDP (17)
+ * Header Checksum: 0xa2ed [correct]
+ * [Header checksum status: Good]
+ * [Calculated Checksum: 0xa2ed]
+ * Source Address: 192.168.38.63
+ * Destination Address: 192.168.44.40
+ * User Datagram Protocol, Src Port: 55298, Dst Port: 53
+ * Source Port: 55298
+ * Destination Port: 53
+ * Length: 40
+ * Checksum: 0xd3e5 [correct]
+ * [Calculated Checksum: 0xd3e5]
+ * [Checksum Status: Good]
+ * [Stream index: 13]
+ * [Timestamps]
+ * [Time since first frame: 0.000000000 seconds]
+ * [Time since previous frame: 0.000000000 seconds]
+ * UDP payload (32 bytes)
+ * Domain Name System (query)
+ * Transaction ID: 0xfc60
+ * Flags: 0x0100 Standard query
+ * 0... .... .... .... = Response: Message is a query
+ * .000 0... .... .... = Opcode: Standard query (0)
+ * .... ..0. .... .... = Truncated: Message is not truncated
+ * .... ...1 .... .... = Recursion desired: Do query recursively
+ * .... .... .0.. .... = Z: reserved (0)
+ * .... .... ...0 .... = Non-authenticated data: Unacceptable
+ * Questions: 1
+ * Answer RRs: 0
+ * Authority RRs: 0
+ * Additional RRs: 0
+ * Queries
+ * deb.debian.org: type A, class IN
+ * Name: deb.debian.org
+ * [Name Length: 14]
+ * [Label Count: 3]
+ * Type: A (Host Address) (1)
+ * Class: IN (0x0001)
+ * [Response In: 51]
+ */
+ let bytes = [
+ 0x48, 0x73, 0x97, 0x96, 0x38, 0x0e, 0x3c, 0xa6, 0xf6, 0x0a, 0xc5, 0xea, 0x08, 0x00,
+ 0x45, 0x00, 0x00, 0x3c, 0x04, 0x0c, 0x00, 0x00, 0x40, 0x11, 0xa2, 0xed, 0xc0, 0xa8,
+ 0x26, 0x3f, 0xc0, 0xa8, 0x2c, 0x28, 0xd8, 0x02, 0x00, 0x35, 0x00, 0x28, 0xd3, 0xe5,
+ 0xfc, 0x60, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x64,
+ 0x65, 0x62, 0x06, 0x64, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x03, 0x6f, 0x72, 0x67, 0x00,
+ 0x00, 0x01, 0x00, 0x01, /* DNS END */
+ ];
+
+ let mut packet = Packet::new(&bytes, bytes.len() as u32);
+ let action = packet.handle();
+ println!("{:?}, {:?}", packet, action);
+ // println!("{:#?}, {:?}", packet, action);
+ // dbg!(packet);
+
+ // assert_eq!(0, 1);
+ }
+
+ #[test]
+ fn test_packet_handle2() {
+ /*
+ * Frame 217: 131 bytes on wire (1048 bits), 131 bytes captured (1048 bits) on interface en0, id 0
+ * Section number: 1
+ * Interface id: 0 (en0)
+ * Interface name: en0
+ * Interface description: Wi-Fi
+ * Encapsulation type: Ethernet (1)
+ * Arrival Time: Aug 2, 2023 11:49:21.582237000 CST
+ * [Time shift for this packet: 0.000000000 seconds]
+ * Epoch Time: 1690948161.582237000 seconds
+ * [Time delta from previous captured frame: 0.000042000 seconds]
+ * [Time delta from previous displayed frame: 0.000000000 seconds]
+ * [Time since reference or first frame: 4.905717000 seconds]
+ * Frame Number: 217
+ * Frame Length: 131 bytes (1048 bits)
+ * Capture Length: 131 bytes (1048 bits)
+ * [Frame is marked: False]
+ * [Frame is ignored: False]
+ * [Protocols in frame: eth:ethertype:ip:tcp:http]
+ * [Coloring Rule Name: HTTP]
+ * [Coloring Rule String: http || tcp.port == 80 || http2]
+ * Ethernet II, Src: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea), Dst: NewH3CTe_96:38:0e (48:73:97:96:38:0e)
+ * Destination: NewH3CTe_96:38:0e (48:73:97:96:38:0e)
+ * Address: NewH3CTe_96:38:0e (48:73:97:96:38:0e)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Source: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea)
+ * Address: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Type: IPv4 (0x0800)
+ * Internet Protocol Version 4, Src: 192.168.38.63, Dst: 182.61.200.6
+ * 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: 117
+ * Identification: 0x0000 (0)
+ * 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: TCP (6)
+ * Header Checksum: 0xd557 [correct]
+ * [Header checksum status: Good]
+ * [Calculated Checksum: 0xd557]
+ * Source Address: 192.168.38.63
+ * Destination Address: 182.61.200.6
+ * Transmission Control Protocol, Src Port: 57016, Dst Port: 80, Seq: 1, Ack: 1, Len: 77
+ * Source Port: 57016
+ * Destination Port: 80
+ * [Stream index: 9]
+ * [Conversation completeness: Complete, WITH_DATA (31)]
+ * [TCP Segment Len: 77]
+ * Sequence Number: 1 (relative sequence number)
+ * Sequence Number (raw): 1965697618
+ * [Next Sequence Number: 78 (relative sequence number)]
+ * Acknowledgment Number: 1 (relative ack number)
+ * Acknowledgment number (raw): 4259318185
+ * 0101 .... = Header Length: 20 bytes (5)
+ * Flags: 0x018 (PSH, 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
+ * .... .... 1... = Push: Set
+ * .... .... .0.. = Reset: Not set
+ * .... .... ..0. = Syn: Not set
+ * .... .... ...0 = Fin: Not set
+ * [TCP Flags: ·······AP···]
+ * Window: 4096
+ * [Calculated window size: 262144]
+ * [Window size scaling factor: 64]
+ * Checksum: 0x7f51 [correct]
+ * [Checksum Status: Good]
+ * [Calculated Checksum: 0x7f51]
+ * Urgent Pointer: 0
+ * [Timestamps]
+ * [Time since first frame in this TCP stream: 0.010626000 seconds]
+ * [Time since previous frame in this TCP stream: 0.000042000 seconds]
+ * [SEQ/ACK analysis]
+ * [iRTT: 0.010584000 seconds]
+ * [Bytes in flight: 77]
+ * [Bytes sent since last PSH flag: 77]
+ * TCP payload (77 bytes)
+ * Hypertext Transfer Protocol
+ * GET / HTTP/1.1\r\n
+ * [Expert Info (Chat/Sequence): GET / HTTP/1.1\r\n]
+ * [GET / HTTP/1.1\r\n]
+ * [Severity level: Chat]
+ * [Group: Sequence]
+ * Request Method: GET
+ * Request URI: /
+ * Request Version: HTTP/1.1
+ * Host: www.baidu.com\r\n
+ * User-Agent: curl/7.64.1\r\n
+ */
+ // Accept: */*\r\n
+ /* \r\n
+ * [Full request URI: http://www.baidu.com/]
+ * [HTTP request 1/1]
+ * [Response in frame: 220]
+ */
+ let bytes = [
+ 0x48, 0x73, 0x97, 0x96, 0x38, 0x0e, 0x3c, 0xa6, 0xf6, 0x0a, 0xc5, 0xea, 0x08, 0x00,
+ 0x45, 0x00, 0x00, 0x75, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, 0xd5, 0x57, 0xc0, 0xa8,
+ 0x26, 0x3f, 0xb6, 0x3d, 0xc8, 0x06, 0xde, 0xb8, 0x00, 0x50, 0x75, 0x2a, 0x2a, 0x52,
+ 0xfd, 0xe0, 0x09, 0xa9, 0x50, 0x18, 0x10, 0x00, 0x7f, 0x51, 0x00, 0x00, 0x47, 0x45,
+ 0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a,
+ 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x62, 0x61, 0x69, 0x64,
+ 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67,
+ 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x63, 0x75, 0x72, 0x6c, 0x2f, 0x37, 0x2e, 0x36, 0x34,
+ 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f,
+ 0x2a, 0x0d, 0x0a, 0x0d, 0x0a, /* HTTP END */
+ ];
+
+ let mut packet = Packet::new(&bytes, bytes.len() as u32);
+ let action = packet.handle();
+ println!("{:?}, {:?}", packet, action);
+ // println!("{:#?}, {:?}", packet, action);
+ // dbg!(packet);
+
+ // assert_eq!(0, 1);
+ }
+}
diff --git a/src/protocol/http.rs b/src/protocol/http.rs
new file mode 100644
index 0000000..de6476f
--- /dev/null
+++ b/src/protocol/http.rs
@@ -0,0 +1,20 @@
+use nom::IResult;
+
+#[allow(non_camel_case_types)]
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct HTTP_MESSAGE {
+ // TODO
+}
+
+impl HTTP_MESSAGE {
+ pub fn new() -> HTTP_MESSAGE {
+ HTTP_MESSAGE {
+ // TODO
+ }
+ }
+ pub fn decode(input: &[u8]) -> IResult<&[u8], HTTP_MESSAGE> {
+ let message = HTTP_MESSAGE::new();
+ // TODO
+ Ok((input, message))
+ }
+}
diff --git a/src/protocol/ipv4.rs b/src/protocol/ipv4.rs
index 3aaa182..4f07926 100644
--- a/src/protocol/ipv4.rs
+++ b/src/protocol/ipv4.rs
@@ -83,6 +83,8 @@ impl IPv4Header {
let (input, source_address) = address_v4_decode(input)?;
let (input, dest_address) = address_v4_decode(input)?;
+ // TODO IPv4 Options Decode
+
Ok((
input,
IPv4Header {
diff --git a/src/protocol/ipv6.rs b/src/protocol/ipv6.rs
index 283172b..f21c4da 100644
--- a/src/protocol/ipv6.rs
+++ b/src/protocol/ipv6.rs
@@ -82,6 +82,8 @@ impl IPv6Header {
let (input, source_address) = address_v6_decode(input)?;
let (input, dest_address) = address_v6_decode(input)?;
+ // TODO IPv6 Ext Header Decode
+
Ok((
input,
IPv6Header {
diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs
index 3427b8b..31046cb 100644
--- a/src/protocol/mod.rs
+++ b/src/protocol/mod.rs
@@ -4,4 +4,5 @@ pub mod ipv4;
pub mod ipv6;
pub mod udp;
pub mod tcp;
-pub mod dns; \ No newline at end of file
+pub mod dns;
+pub mod http; \ No newline at end of file