net_trace/
packet.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct NetworkPacket {
    pub timestamp: DateTime<Utc>,
    pub ethernet_layer: EthernetFrame,
    pub ip_layer: IPv4Packet,
    pub tcp_layer: TCPSegment,
    pub application_layer: ApplicationData,
}

/// Ethernet (Layer 2) Frame
#[derive(Debug, Serialize, Deserialize)]
pub struct EthernetFrame {
    pub source_mac: [u8; 6],
    pub destination_mac: [u8; 6],
    pub ethertype: u16,  // 0x0800 for IPv4
    pub frame_check_sequence: u32,
}

/// IPv4 (Layer 3) Packet
#[derive(Debug, Serialize, Deserialize)]
pub struct IPv4Packet {
    pub version: u8,          // 4 for IPv4
    pub ihl: u8,             // Internet Header Length
    pub dscp: u8,            // Differentiated Services Code Point
    pub ecn: u8,             // Explicit Congestion Notification
    pub total_length: u16,
    pub identification: u16,
    pub flags: IPv4Flags,
    pub fragment_offset: u16,
    pub ttl: u8,             // Time To Live
    pub protocol: u8,        // 6 for TCP
    pub header_checksum: u16,
    pub source_ip: [u8; 4],
    pub destination_ip: [u8; 4],
    pub options: Vec<u8>,    // Optional IPv4 options
}

/// IPv4 Flags
#[derive(Debug, Serialize, Deserialize)]
pub struct IPv4Flags {
    pub reserved: bool,      // Must be zero
    pub dont_fragment: bool,
    pub more_fragments: bool,
}

/// TCP (Layer 4) Segment
#[derive(Debug, Serialize, Deserialize)]
pub struct TCPSegment {
    pub source_port: u16,
    pub destination_port: u16,
    pub sequence_number: u32,
    pub acknowledgment_number: u32,
    pub data_offset: u8,     // Header length in 32-bit words
    pub flags: TCPFlags,
    pub window_size: u16,
    pub checksum: u16,
    pub urgent_pointer: u16,
    pub options: Vec<TCPOption>,
}

/// TCP Flags
#[derive(Debug, Serialize, Deserialize)]
pub struct TCPFlags {
    pub fin: bool,          // Finish
    pub syn: bool,          // Synchronize
    pub rst: bool,          // Reset
    pub psh: bool,          // Push
    pub ack: bool,          // Acknowledgment
    pub urg: bool,          // Urgent
    pub ece: bool,          // ECN-Echo
    pub cwr: bool,          // Congestion Window Reduced
}

/// TCP Option
#[derive(Debug, Serialize, Deserialize)]
pub struct TCPOption {
    pub kind: u8,
    pub length: u8,
    pub data: Vec<u8>,
}

/// Application Layer Data
#[derive(Debug, Serialize, Deserialize)]
pub struct ApplicationData {
    pub protocol: ApplicationProtocol,
    pub payload: Vec<u8>,
}

/// Supported Application Protocols
#[derive(Debug, Serialize, Deserialize)]
pub enum ApplicationProtocol {
    HTTP,
    HTTPS,
    FTP,
    SSH,
    SMTP,
    DNS,
    Custom(String),
}

/// Implementation for NetworkPacket
impl NetworkPacket {
    /// Calculate the total size of the packet in bytes
    pub fn total_size(&self) -> usize {
        14 + // Ethernet header (without FCS)
        20 + self.ip_layer.options.len() + // IPv4 header
        20 + self.tcp_layer.options.iter().map(|opt| opt.length as usize).sum::<usize>() + // TCP header
        self.application_layer.payload.len() // Application data
    }
    
    /// Check if packet is part of a TCP handshake
    pub fn is_handshake(&self) -> bool {
        self.tcp_layer.flags.syn || self.tcp_layer.flags.fin
    }
    
    /// Get the application protocol as a string
    pub fn get_protocol_string(&self) -> String {
        match &self.application_layer.protocol {
            ApplicationProtocol::HTTP => "HTTP".to_string(),
            ApplicationProtocol::HTTPS => "HTTPS".to_string(),
            ApplicationProtocol::FTP => "FTP".to_string(),
            ApplicationProtocol::SSH => "SSH".to_string(),
            ApplicationProtocol::SMTP => "SMTP".to_string(),
            ApplicationProtocol::DNS => "DNS".to_string(),
            ApplicationProtocol::Custom(proto) => proto.clone(),
        }
    }
}