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#[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
30pub fn parse_pcap<P: AsRef<Path>>(pcap_path: P) -> Result<Vec<NetworkPacket>, PcapError> {
32 if !is_tshark_installed() {
34 return Err(PcapError::TsharkNotFound);
35 }
36
37 let output = Command::new("tshark")
39 .args([
40 "-r", pcap_path.as_ref().to_str().unwrap(),
41 "-T", "json",
42 "-x", "-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", ])
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 let network_packets = packets.into_iter()
74 .filter_map(|packet| parse_packet_json(packet).ok())
75 .collect();
76
77 Ok(network_packets)
78}
79
80fn 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 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 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
214fn parse_application_layer(layers: &Value) -> Result<ApplicationData, PcapError> {
216 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(), })
257}
258fn 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
270fn 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
282fn 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
298fn is_tshark_installed() -> bool {
300 Command::new("tshark")
301 .arg("--version")
302 .output()
303 .is_ok()
304}