net_trace/
parser.rs

1use std::process::Command;
2use std::path::Path;
3use std::io::{self};
4use serde_json::{Value};
5use chrono::DateTime;
6use crate::packet::*;
7use chrono::Utc;
8
9/// Error types for PCAP parsing
10#[derive(Debug)]
11pub enum PcapError {
12    IoError(io::Error),
13    TsharkNotFound,
14    ParseError(String),
15    JsonError(serde_json::Error),
16}
17
18impl From<io::Error> for PcapError {
19    fn from(error: io::Error) -> Self {
20        PcapError::IoError(error)
21    }
22}
23
24impl From<serde_json::Error> for PcapError {
25    fn from(error: serde_json::Error) -> Self {
26        PcapError::JsonError(error)
27    }
28}
29
30/// Parse a PCAP file using tshark and return a vector of NetworkPackets
31pub fn parse_pcap<P: AsRef<Path>>(pcap_path: P) -> Result<Vec<NetworkPacket>, PcapError> {
32    // Check if tshark is available
33    if !is_tshark_installed() {
34        return Err(PcapError::TsharkNotFound);
35    }
36
37    // Run tshark command to convert pcap to JSON
38    let output = Command::new("tshark")
39        .args([
40            "-r", pcap_path.as_ref().to_str().unwrap(),
41            "-T", "json",
42            "-x",  // Include hex dump
43            // Fields we want to capture
44            "-e", "frame.time_epoch",
45            "-e", "eth.src",
46            "-e", "eth.dst",
47            "-e", "eth.type",
48            "-e", "ip.src",
49            "-e", "ip.dst",
50            "-e", "ip.proto",
51            "-e", "tcp.srcport",
52            "-e", "tcp.dstport",
53            "-e", "tcp.seq",
54            "-e", "tcp.ack",
55            "-e", "tcp.flags",
56            "-e", "tcp.window_size",
57            "-e", "tcp.options",
58            "-J", "tcp",  // Only TCP packets
59        ])
60        .output()?;
61
62    if !output.status.success() {
63        println!("Error running tshark: {}", String::from_utf8_lossy(&output.stderr));
64        return Err(PcapError::ParseError(
65            String::from_utf8_lossy(&output.stderr).to_string()
66        ));
67    }
68
69    let json_str = String::from_utf8_lossy(&output.stdout);
70    let packets: Vec<Value> = serde_json::from_str(&json_str)?;
71
72    // Parse JSON into NetworkPacket structs
73    let network_packets = packets.into_iter()
74        .filter_map(|packet| parse_packet_json(packet).ok())
75        .collect();
76
77    Ok(network_packets)
78}
79
80/// Parse a single packet from JSON to NetworkPacket struct
81fn parse_packet_json(json: Value) -> Result<NetworkPacket, PcapError> {
82    let layers = json.get("_source")
83        .and_then(|src| src.get("layers"))
84        .ok_or_else(|| PcapError::ParseError("Invalid JSON structure".to_string()))?;
85
86    // Parse timestamp - get first element from array
87    let timestamp = layers.get("frame.time_epoch")
88        .and_then(|t| t.as_array())
89        .and_then(|arr| arr.first())
90        .and_then(|t| t.as_str())
91        .and_then(|t| t.parse::<f64>().ok())
92        .map(|t| {
93            let secs = t.trunc() as i64;
94            let nsecs = (t.fract() * 1_000_000_000.0) as u32;
95            DateTime::<Utc>::from_timestamp(secs, nsecs)
96                .unwrap_or_default()
97        })
98        .ok_or_else(|| PcapError::ParseError("Invalid timestamp".to_string()))?;
99
100    // Parse other layers
101    let ethernet_layer = parse_ethernet_layer(layers)?;
102    let ip_layer = parse_ip_layer(layers)?;
103    let tcp_layer = parse_tcp_layer(layers)?;
104    let application_layer = parse_application_layer(layers)?;
105
106    Ok(NetworkPacket {
107        timestamp,
108        ethernet_layer,
109        ip_layer,
110        tcp_layer,
111        application_layer,
112    })
113}
114
115fn parse_ethernet_layer(layers: &Value) -> Result<EthernetFrame, PcapError> {
116    Ok(EthernetFrame {
117        source_mac: parse_mac_address(layers.get("eth.src")
118            .and_then(|mac| mac.as_array())
119            .and_then(|arr| arr.first())
120            .and_then(|mac| mac.as_str())
121            .ok_or_else(|| PcapError::ParseError("Invalid source MAC".to_string()))?),
122        destination_mac: parse_mac_address(layers.get("eth.dst")
123            .and_then(|mac| mac.as_array())
124            .and_then(|arr| arr.first())
125            .and_then(|mac| mac.as_str())
126            .ok_or_else(|| PcapError::ParseError("Invalid destination MAC".to_string()))?),
127        ethertype: layers.get("eth.type")
128            .and_then(|t| t.as_array())
129            .and_then(|arr| arr.first())
130            .and_then(|t| t.as_str())
131            .and_then(|t| u16::from_str_radix(t, 16).ok())
132            .unwrap_or(0x0800),
133        frame_check_sequence: 0,
134    })
135}
136
137fn parse_ip_layer(layers: &Value) -> Result<IPv4Packet, PcapError> {
138    Ok(IPv4Packet {
139        version: 4,
140        ihl: 5,
141        dscp: 0,
142        ecn: 0,
143        total_length: 0,
144        identification: 0,
145        flags: IPv4Flags {
146            reserved: false,
147            dont_fragment: false,
148            more_fragments: false,
149        },
150        fragment_offset: 0,
151        ttl: 64,
152        protocol: 6,
153        header_checksum: 0,
154        source_ip: parse_ip_address(layers.get("ip.src")
155            .and_then(|ip| ip.as_array())
156            .and_then(|arr| arr.first())
157            .and_then(|ip| ip.as_str())
158            .ok_or_else(|| PcapError::ParseError("Invalid source IP".to_string()))?),
159        destination_ip: parse_ip_address(layers.get("ip.dst")
160            .and_then(|ip| ip.as_array())
161            .and_then(|arr| arr.first())
162            .and_then(|ip| ip.as_str())
163            .ok_or_else(|| PcapError::ParseError("Invalid destination IP".to_string()))?),
164        options: Vec::new(),
165    })
166}
167
168fn parse_tcp_layer(layers: &Value) -> Result<TCPSegment, PcapError> {
169    let flags = parse_tcp_flags(layers.get("tcp.flags")
170        .and_then(|f| f.as_array())
171        .and_then(|arr| arr.first())
172        .and_then(|f| f.as_str())
173        .unwrap_or("0x000"));
174
175    Ok(TCPSegment {
176        source_port: layers.get("tcp.srcport")
177            .and_then(|p| p.as_array())
178            .and_then(|arr| arr.first())
179            .and_then(|p| p.as_str())
180            .and_then(|p| p.parse().ok())
181            .unwrap_or(0),
182        destination_port: layers.get("tcp.dstport")
183            .and_then(|p| p.as_array())
184            .and_then(|arr| arr.first())
185            .and_then(|p| p.as_str())
186            .and_then(|p| p.parse().ok())
187            .unwrap_or(0),
188        sequence_number: layers.get("tcp.seq")
189            .and_then(|s| s.as_array())
190            .and_then(|arr| arr.first())
191            .and_then(|s| s.as_str())
192            .and_then(|s| s.parse().ok())
193            .unwrap_or(0),
194        acknowledgment_number: layers.get("tcp.ack")
195            .and_then(|a| a.as_array())
196            .and_then(|arr| arr.first())
197            .and_then(|a| a.as_str())
198            .and_then(|a| a.parse().ok())
199            .unwrap_or(0),
200        data_offset: 5,
201        flags,
202        window_size: layers.get("tcp.window_size")
203            .and_then(|w| w.as_array())
204            .and_then(|arr| arr.first())
205            .and_then(|w| w.as_str())
206            .and_then(|w| w.parse().ok())
207            .unwrap_or(0),
208        checksum: 0,
209        urgent_pointer: 0,
210        options: Vec::new(),
211    })
212}
213
214/// Parse application layer from JSON
215fn parse_application_layer(layers: &Value) -> Result<ApplicationData, PcapError> {
216    // Determine protocol based on ports
217    let src_port = layers.get("tcp.srcport")
218        .and_then(|p| p.as_array())
219        .and_then(|arr| arr.first())
220        .and_then(|p| p.as_str())
221        .and_then(|p| p.parse::<u16>().ok())
222        .unwrap_or(0);
223    let dst_port = layers.get("tcp.dstport")
224        .and_then(|p| p.as_array())
225        .and_then(|arr| arr.first())
226        .and_then(|p| p.as_str())
227        .and_then(|p| p.parse::<u16>().ok())
228        .unwrap_or(0);
229
230    let protocol = match (src_port, dst_port) {
231        (80, _) | (_, 80) => ApplicationProtocol::HTTP,
232        (8080, _) | (_, 8080) => ApplicationProtocol::HTTP,
233        (443, _) | (_, 443) => ApplicationProtocol::HTTPS,
234        (20, _) | (_, 20) => ApplicationProtocol::FTP,
235        (21, _) | (_, 21) => ApplicationProtocol::FTP,
236        (22, _) | (_, 22) => ApplicationProtocol::SSH,
237        (25, _) | (_, 25) => ApplicationProtocol::SMTP,
238        (53, _) | (_, 53) => ApplicationProtocol::DNS,
239        (69, _) | (_, 69) => ApplicationProtocol::DNS,
240        (123, _) | (_, 123) => ApplicationProtocol::NTP,
241        (137, _) | (_, 137) => ApplicationProtocol::NetBIOS,
242        (138, _) | (_, 138) => ApplicationProtocol::NetBIOS,
243        (139, _) | (_, 139) => ApplicationProtocol::NetBIOS,
244        (143, _) | (_, 143) => ApplicationProtocol::IMAP,
245        (161, _) | (_, 161) => ApplicationProtocol::SNMP,
246        (162, _) | (_, 162) => ApplicationProtocol::SNMP,
247        (389, _) | (_, 389) => ApplicationProtocol::LDAP,
248        (445, _) | (_, 445) => ApplicationProtocol::SMB,
249        (464, _) | (_, 464) => ApplicationProtocol::Kerberos,
250        _ => ApplicationProtocol::Custom(format!("PORT_{}_{}", src_port, dst_port)),
251    };
252
253    Ok(ApplicationData {
254        protocol,
255        payload: Vec::new(), // Parse payload from hex dump if needed
256    })
257}
258/// Helper function to parse MAC address string into bytes
259fn parse_mac_address(mac_str: &str) -> [u8; 6] {
260    let mut mac = [0u8; 6];
261    let parts: Vec<&str> = mac_str.split(':').collect();
262    for (i, part) in parts.iter().enumerate() {
263        if i < 6 {
264            mac[i] = u8::from_str_radix(part, 16).unwrap_or(0);
265        }
266    }
267    mac
268}
269
270/// Helper function to parse IP address string into bytes
271fn parse_ip_address(ip_str: &str) -> [u8; 4] {
272    let mut ip = [0u8; 4];
273    let parts: Vec<&str> = ip_str.split('.').collect();
274    for (i, part) in parts.iter().enumerate() {
275        if i < 4 {
276            ip[i] = part.parse().unwrap_or(0);
277        }
278    }
279    ip
280}
281
282/// Helper function to parse TCP flags
283fn parse_tcp_flags(flags_str: &str) -> TCPFlags {
284    let flags_value = u16::from_str_radix(&flags_str.trim_start_matches("0x"), 16).unwrap_or(0);
285    
286    TCPFlags {
287        fin: flags_value & 0x001 != 0,
288        syn: flags_value & 0x002 != 0,
289        rst: flags_value & 0x004 != 0,
290        psh: flags_value & 0x008 != 0,
291        ack: flags_value & 0x010 != 0,
292        urg: flags_value & 0x020 != 0,
293        ece: flags_value & 0x040 != 0,
294        cwr: flags_value & 0x080 != 0,
295    }
296}
297
298/// Check if tshark is installed
299fn is_tshark_installed() -> bool {
300    Command::new("tshark")
301        .arg("--version")
302        .output()
303        .is_ok()
304}