Skip to content

Commit e43d95a

Browse files
committed
Use our fork of the pcap-file crate.
1 parent 694fe68 commit e43d95a

File tree

5 files changed

+74
-146
lines changed

5 files changed

+74
-146
lines changed

Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ bytemuck_derive = "1.5.0"
3232
gtk = { version = "0.8.0", package = "gtk4", features = ["v4_4"] }
3333
num_enum = "0.7.2"
3434
once_cell = "1.19.0"
35-
pcap-file = "2.0.0"
35+
pcap-file = { version = "3.0.0-rc2", package = "pcap-file-gsg" }
3636
tempfile = "3.9.0"
3737
bitfield = "0.14.0"
3838
num-format = "0.4.4"

src/capture.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::ops::Range;
88
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64};
99
use std::sync::atomic::Ordering::{Acquire, Release};
1010
use std::sync::Arc;
11-
use std::time::SystemTime;
11+
use std::time::Duration;
1212
use std::mem::size_of;
1313

1414
use crate::database::{
@@ -58,8 +58,8 @@ pub struct CaptureMetadata {
5858
pub iface_snaplen: Option<NonZeroU32>,
5959

6060
// Fields corresponding to PcapNG interface statistics.
61-
pub start_time: Option<SystemTime>,
62-
pub end_time: Option<SystemTime>,
61+
pub start_time: Option<Duration>,
62+
pub end_time: Option<Duration>,
6363
pub dropped: Option<u64>,
6464
}
6565

src/file.rs

Lines changed: 54 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,16 @@ use std::borrow::Cow;
22
use std::io::{BufReader, BufWriter, Read, Write};
33
use std::mem::size_of;
44
use std::num::NonZeroU32;
5-
use std::ops::Deref;
65
use std::sync::Arc;
7-
use std::time::{SystemTime, Duration};
6+
use std::time::Duration;
87

98
use anyhow::{Context, Error, anyhow};
10-
use byteorder_slice::{
11-
ByteOrder, BigEndian, LittleEndian,
12-
result::ReadSlice
13-
};
149
use pcap_file::{
1510
pcap::{PcapReader, PcapHeader, PcapWriter, RawPcapPacket},
1611
pcapng::{
17-
PcapNgReader, PcapNgWriter, PcapNgBlock,
12+
PcapNgReader, PcapNgWriter,
1813
blocks::{
19-
Block, RawBlock,
20-
ENHANCED_PACKET_BLOCK,
14+
Block,
2115
section_header:: {
2216
SectionHeaderBlock,
2317
SectionHeaderOption,
@@ -34,7 +28,6 @@ use pcap_file::{
3428
},
3529
},
3630
DataLink,
37-
Endianness,
3831
TsResolution,
3932
};
4033
use once_cell::sync::Lazy;
@@ -207,47 +200,26 @@ impl GenericPacket for PacketWrapper<RawPcapPacket<'_>> {
207200
pub struct PcapNgLoader<Source: Read> {
208201
pcap: PcapNgReader<BufReader<Source>>,
209202
initial_metadata: Option<CaptureMetadata>,
210-
bytes_read: u64,
211-
endianness: Endianness,
212-
interface_ts_units: Vec<u64>,
213-
ts_start: Option<u64>,
203+
interface_seen: bool,
204+
ts_start: Option<Duration>,
214205
}
215206

216207
/// Saver for pcap-ng format.
217-
pub struct PcapNgSaver<Dest: Write> {
218-
pcap: PcapNgWriter<BufWriter<Dest>>,
208+
pub struct PcapNgSaver<'s, Dest: Write> {
209+
pcap: PcapNgWriter<'s, BufWriter<Dest>>,
219210
meta: Arc<CaptureMetadata>,
220211
}
221212

222-
/// Helper for parsing Enhanced Packet Blocks.
223-
fn parse_epb<B: ByteOrder>(raw_block: &RawBlock<'_>)
224-
-> Result<(usize, u64, usize), Error>
225-
{
226-
let mut slice = raw_block.body.deref();
227-
let interface_id = slice.read_u32::<B>()? as usize;
228-
let timestamp_hi = slice.read_u32::<B>()? as u64;
229-
let timestamp_lo = slice.read_u32::<B>()? as u64;
230-
let length = slice.read_u32::<B>()? as usize;
231-
let timestamp = (timestamp_hi << 32) + timestamp_lo;
232-
Ok((interface_id, timestamp, length))
233-
}
234-
235213
impl<Source> GenericLoader<Source>
236214
for PcapNgLoader<Source>
237215
where Source: Read
238216
{
239-
type PacketData<'p> = PacketWrapper<(RawBlock<'p>, usize)>;
217+
type PacketData<'p> = PacketWrapper<EnhancedPacketBlock<'p>>;
240218

241219
fn new(source: Source) -> Result<Self, Error> {
242220
let reader = BufReader::new(source);
243221
let pcap = PcapNgReader::new(reader)?;
244222
let section_header = pcap.section();
245-
let endianness = section_header.endianness;
246-
let header_length = {
247-
let mut tmp = Vec::<u8>::new();
248-
section_header.write_to::<LittleEndian, Vec<u8>>(&mut tmp)?;
249-
tmp.len()
250-
};
251223
let initial_metadata = Some({
252224
let mut meta = CaptureMetadata::default();
253225
for option in &section_header.options {
@@ -273,70 +245,54 @@ where Source: Read
273245
Ok(PcapNgLoader{
274246
pcap,
275247
initial_metadata,
276-
endianness,
277-
interface_ts_units: vec![],
278-
bytes_read: header_length as u64,
248+
interface_seen: false,
279249
ts_start: None
280250
})
281251
}
282252

283253
fn next(&mut self) -> LoaderItem<impl GenericPacket> {
284-
use Endianness::*;
285254
use DataLink::*;
286255
use LoaderItem::*;
287256
if let Some(meta) = self.initial_metadata.take() {
288257
return Metadata(Box::new(meta))
289258
}
290-
let raw_block = match self.pcap.next_raw_block() {
259+
let total_bytes_read = self.pcap.bytes_parsed();
260+
let block = match self.pcap.next_block() {
291261
None => return End,
292262
Some(Err(e)) => return LoadError(anyhow!(e)),
293263
Some(Ok(block)) => block
294264
};
295-
self.bytes_read += raw_block.initial_len as u64;
296-
if raw_block.type_ == ENHANCED_PACKET_BLOCK {
297-
let parse_result = match self.endianness {
298-
Big => parse_epb::<BigEndian>(&raw_block),
299-
Little => parse_epb::<LittleEndian>(&raw_block),
300-
};
301-
let (interface_id, ts_value, length) = match parse_result {
302-
Ok(values) => values,
303-
Err(e) => return LoadError(anyhow!(e)),
304-
};
305-
let ts_unit = match self.interface_ts_units.get(interface_id) {
306-
Some(unit) => unit,
307-
None => return LoadError(anyhow!(
308-
"Missing block for interface {interface_id}"
309-
))
310-
};
311-
let timestamp_ns = if let Some(ts_start) = self.ts_start {
312-
ts_unit * (ts_value - ts_start)
313-
} else {
314-
self.ts_start = Some(ts_value);
315-
0
316-
};
317-
return Packet(
318-
PacketWrapper {
319-
packet_data: (raw_block, length),
320-
timestamp_ns,
321-
total_bytes_read: self.bytes_read,
322-
}
323-
)
324-
}
325-
let parsed_block = match self.endianness {
326-
Big => raw_block.try_into_block::<BigEndian>(),
327-
Little => raw_block.try_into_block::<LittleEndian>(),
328-
};
329-
match parsed_block {
330-
Err(e) => return LoadError(anyhow!(e)),
331-
Ok(Block::SectionHeader(_)) =>
332-
return LoadError(anyhow!(
265+
match block {
266+
Block::EnhancedPacket(epb) => {
267+
let timestamp_ns: u128 = if let Some(ts_start) = self.ts_start {
268+
(epb.timestamp - ts_start).as_nanos()
269+
} else {
270+
self.ts_start = Some(epb.timestamp);
271+
0
272+
};
273+
let timestamp_ns: u64 = match timestamp_ns.try_into() {
274+
Ok(ns) => ns,
275+
Err(e) => return LoadError(anyhow!(e))
276+
};
277+
Packet(
278+
PacketWrapper {
279+
packet_data: epb,
280+
timestamp_ns,
281+
total_bytes_read,
282+
}
283+
)
284+
},
285+
Block::SectionHeader(_) =>
286+
LoadError(anyhow!(
333287
"Multiple sections are not supported.")),
334-
Ok(Block::InterfaceDescription(interface)) => {
288+
Block::InterfaceDescription(interface) => {
335289
use InterfaceDescriptionOption::*;
336290
use Speed::*;
337-
if !self.interface_ts_units.is_empty() {
291+
if self.interface_seen {
338292
return LoadError(anyhow!(
339293
"Multiple interfaces are not supported"))
294+
} else {
295+
self.interface_seen = true;
340296
}
341297
let mut meta = CaptureMetadata::default();
342298
match interface.linktype {
@@ -355,17 +311,8 @@ where Source: Read
355311
interface.linktype)),
356312
};
357313
meta.iface_snaplen = NonZeroU32::new(interface.snaplen);
358-
let mut ts_units_specified = false;
359314
for option in interface.options {
360315
match option {
361-
IfTsResol(res) => {
362-
let ts_unit = 1_000_000_000 / match res {
363-
0x00..=0x7f => 10u64.pow(res as u32),
364-
0x80..=0xff => 2u64.pow((res & 0x7f) as u32)
365-
};
366-
self.interface_ts_units.push(ts_unit);
367-
ts_units_specified = true;
368-
},
369316
IfDescription(desc) => {
370317
meta.iface_desc.replace(desc.to_string());
371318
},
@@ -378,41 +325,23 @@ where Source: Read
378325
_ => {}
379326
};
380327
}
381-
if !ts_units_specified {
382-
self.interface_ts_units.push(1000);
383-
}
384-
return Metadata(Box::new(meta))
328+
Metadata(Box::new(meta))
385329
},
386-
Ok(Block::InterfaceStatistics(stats)) => {
330+
Block::InterfaceStatistics(stats) => {
387331
use InterfaceStatisticsOption::*;
388332
let mut meta = CaptureMetadata::default();
389333
for option in stats.options {
390334
match option {
391-
IsbStartTime(time) => {
392-
meta.start_time.replace(
393-
SystemTime::UNIX_EPOCH + Duration::from_nanos(
394-
time * self.interface_ts_units[0]
395-
)
396-
);
397-
},
398-
IsbEndTime(time) => {
399-
meta.end_time.replace(
400-
SystemTime::UNIX_EPOCH + Duration::from_nanos(
401-
time * self.interface_ts_units[0]
402-
)
403-
);
404-
},
405-
IsbIfDrop(pkts) => {
406-
meta.dropped.replace(pkts);
407-
},
335+
IsbStartTime(time) => { meta.start_time.replace(time); },
336+
IsbEndTime(time) => { meta.end_time.replace(time); },
337+
IsbIfDrop(pkts) => { meta.dropped.replace(pkts); },
408338
_ => {}
409339
};
410340
}
411-
return Metadata(Box::new(meta))
341+
Metadata(Box::new(meta))
412342
},
413-
_ => {}
414-
};
415-
Ignore
343+
_ => Ignore
344+
}
416345
}
417346
}
418347

@@ -430,10 +359,8 @@ fn speed_bps(speed: &Speed) -> Option<u64> {
430359
}
431360
}
432361

433-
fn time_nanos(time: &SystemTime) -> Option<u64> {
434-
time.duration_since(SystemTime::UNIX_EPOCH)
435-
.ok()
436-
.and_then(|duration| duration.as_nanos().try_into().ok())
362+
fn duration(duration: &Duration) -> Option<Duration> {
363+
Some(*duration)
437364
}
438365

439366
macro_rules! option {
@@ -468,16 +395,16 @@ fn stats_options(meta: &CaptureMetadata)
468395
{
469396
use InterfaceStatisticsOption::*;
470397
let mut opt = Vec::new();
471-
option!(meta, opt, start_time, IsbStartTime, time_nanos);
472-
option!(meta, opt, end_time, IsbEndTime, time_nanos);
398+
option!(meta, opt, start_time, IsbStartTime, duration);
399+
option!(meta, opt, end_time, IsbEndTime, duration);
473400
if let Some(pkts) = meta.dropped {
474401
opt.push(IsbIfDrop(pkts));
475402
}
476403
opt
477404
}
478405

479406
impl<Dest> GenericSaver<Dest>
480-
for PcapNgSaver<Dest>
407+
for PcapNgSaver<'_, Dest>
481408
where Self: Sized, Dest: Write
482409
{
483410
fn new(dest: Dest, meta: Arc<CaptureMetadata>) -> Result<Self, Error> {
@@ -538,12 +465,8 @@ where Self: Sized, Dest: Write
538465
InterfaceStatisticsBlock {
539466
interface_id: 0,
540467
timestamp: match self.meta.end_time {
541-
Some(end) => end
542-
.duration_since(SystemTime::UNIX_EPOCH)?
543-
.as_nanos()
544-
.try_into()
545-
.context("Timestamp overflow")?,
546-
None => 0
468+
Some(end) => end,
469+
None => Duration::from_nanos(0),
547470
},
548471
options: stats_options(&self.meta)
549472
}
@@ -553,11 +476,8 @@ where Self: Sized, Dest: Write
553476
}
554477
}
555478

556-
impl GenericPacket for PacketWrapper<(RawBlock<'_>, usize)> {
557-
fn bytes(&self) -> &[u8] {
558-
let (raw_block, length) = &self.packet_data;
559-
&raw_block.body[20..][..*length]
560-
}
479+
impl GenericPacket for PacketWrapper<EnhancedPacketBlock<'_>> {
480+
fn bytes(&self) -> &[u8] { &self.packet_data.data }
561481
fn timestamp_ns(&self) -> u64 { self.timestamp_ns }
562482
fn total_bytes_read(&self) -> u64 { self.total_bytes_read }
563483
}

0 commit comments

Comments
 (0)