@@ -2,21 +2,28 @@ mod mybufread;
2
2
mod tcp;
3
3
mod tracker;
4
4
5
- use std:: io;
5
+ use std:: {
6
+ io,
7
+ time:: { Duration , SystemTime } ,
8
+ } ;
6
9
7
10
use anyhow:: { bail, Result as AResult } ;
8
11
9
12
use pcap_file:: {
10
13
pcap:: PcapReader ,
11
- pcapng:: { Block , PcapNgReader } ,
14
+ pcapng:: { blocks :: interface_description :: InterfaceDescriptionOption , Block , PcapNgReader } ,
12
15
DataLink ,
13
16
} ;
14
17
18
+ use crate :: event:: Timestamp ;
19
+
15
20
use self :: mybufread:: MyBufReader ;
16
21
pub use self :: tracker:: Tracker ;
17
22
18
23
/// Parse PCAP records from the reader and hand the packets to the Tracker. This
19
24
/// function works with both the old-style PCAP and with PCAP-NG file formats.
25
+ ///
26
+ /// See also https://www.ietf.org/archive/id/draft-tuexen-opsawg-pcapng-04.html
20
27
pub fn parse_pcap_file ( mut rd : impl io:: Read , tracker : & mut Tracker ) -> AResult < ( ) > {
21
28
// read ahead to inspect the file header
22
29
let mut signature = [ 0u8 ; 4 ] ;
@@ -52,11 +59,12 @@ fn parse_legacy_pcap(rd: MyBufReader, tracker: &mut Tracker) -> AResult<()> {
52
59
53
60
while let Some ( pkt) = pcap_reader. next_packet ( ) {
54
61
let pkt = pkt?;
62
+ let timestamp = Timestamp ( pkt. timestamp ) ;
55
63
if pkt. data . len ( ) == header. snaplen as usize {
56
64
bail ! ( "truncated packet" ) ;
57
65
}
58
66
59
- process_packet ( header. datalink , & pkt. data , tracker) ?;
67
+ process_packet ( & timestamp , header. datalink , & pkt. data , tracker) ?;
60
68
}
61
69
62
70
Ok ( ( ) )
@@ -71,22 +79,51 @@ fn parse_pcap_ng(rd: MyBufReader, tracker: &mut Tracker) -> AResult<()> {
71
79
// This mutable holds the latest value we have seen.
72
80
let mut linktype = None ;
73
81
82
+ // Only used for legacy Block::Packet, completely untested
83
+ let mut timestamp_resolution = Duration :: from_micros ( 1 ) ;
84
+
85
+ let mut timestamp: Timestamp = SystemTime :: now ( ) . into ( ) ;
74
86
while let Some ( block) = pcapng_reader. next_block ( ) {
75
87
let data = match block? {
76
88
Block :: InterfaceDescription ( iface) => {
77
89
linktype = Some ( iface. linktype ) ;
90
+ for opt in iface. options {
91
+ // This is all completely untested
92
+ if let InterfaceDescriptionOption :: IfTsResol ( reso) = opt {
93
+ let base = if reso & 0x80 == 0 { 10u32 } else { 2 } ;
94
+ let divisor = base. pow ( reso as u32 & 0x7F ) ;
95
+ timestamp_resolution = Duration :: from_secs ( 1 ) / divisor;
96
+ }
97
+ }
78
98
continue ;
79
99
}
80
- Block :: Packet ( packet) => packet. data ,
81
- Block :: SimplePacket ( packet) => packet. data ,
82
- Block :: EnhancedPacket ( packet) => packet. data ,
100
+ Block :: Packet ( packet) => {
101
+ // This is all completely untested
102
+ let units = packet. timestamp ;
103
+ // Duration can be multiplied by u32, not by u64.
104
+ let units_lo = ( units & 0xFFFF_FFFF ) as u32 ;
105
+ let units_hi = ( units >> 32 ) as u32 ;
106
+ let duration_lo = timestamp_resolution * units_lo;
107
+ let duration_hi = timestamp_resolution * units_hi;
108
+ let duration = duration_hi * 0x1_0000 * 0x1_0000 + duration_lo;
109
+ timestamp = Timestamp ( duration) ;
110
+ packet. data
111
+ }
112
+ Block :: SimplePacket ( packet) => {
113
+ // has no timestamp, keep existing
114
+ packet. data
115
+ }
116
+ Block :: EnhancedPacket ( packet) => {
117
+ timestamp = Timestamp ( packet. timestamp ) ;
118
+ packet. data
119
+ }
83
120
_ => continue ,
84
121
} ;
85
122
86
123
// Broken files might contain packets before the first interface description block.
87
124
// Ignore them.
88
125
if let Some ( lt) = linktype {
89
- process_packet ( lt, & data, tracker) ?;
126
+ process_packet ( & timestamp , lt, & data, tracker) ?;
90
127
}
91
128
}
92
129
@@ -95,11 +132,16 @@ fn parse_pcap_ng(rd: MyBufReader, tracker: &mut Tracker) -> AResult<()> {
95
132
96
133
/// This function is called from both [parse_legacy_pcap] and [parse_pcap_ng]
97
134
/// for each packet in the file.
98
- fn process_packet ( linktype : DataLink , data : & [ u8 ] , tracker : & mut Tracker ) -> AResult < ( ) > {
135
+ fn process_packet (
136
+ timestamp : & Timestamp ,
137
+ linktype : DataLink ,
138
+ data : & [ u8 ] ,
139
+ tracker : & mut Tracker ,
140
+ ) -> AResult < ( ) > {
99
141
// We expect to read ethernet frames but it's also possible for pcap files to
100
142
// capture at the IP level. Right now we only support Ethernet.
101
143
match linktype {
102
- DataLink :: ETHERNET => tracker. process_ethernet ( data) ,
144
+ DataLink :: ETHERNET => tracker. process_ethernet ( timestamp , data) ,
103
145
_ => bail ! ( "pcap file contains packet of type {linktype:?}, this is not supported" ) ,
104
146
}
105
147
}
0 commit comments