@@ -33,11 +33,42 @@ package pcap
33
33
// See http://upstream-tracker.org/versions/libpcap.html
34
34
35
35
#ifndef PCAP_ERROR_TSTAMP_PRECISION_NOTSUP // < v1.5
36
+ #define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12
36
37
37
38
int pcap_set_immediate_mode(pcap_t *p, int mode) {
38
39
return PCAP_ERROR;
39
40
}
40
41
42
+ #define PCAP_TSTAMP_PRECISION_MICRO 0
43
+ #define PCAP_TSTAMP_PRECISION_NANO 1
44
+
45
+ #ifdef WIN32
46
+ pcap_t *pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision,
47
+ char *errbuf) {
48
+ return pcap_hopen_offline(osdf, errbuf);
49
+ }
50
+ #else
51
+ pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
52
+ char *errbuf) {
53
+ return pcap_fopen_offline(fp, errbuf);
54
+ }
55
+ #endif
56
+
57
+ pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
58
+ char *errbuf) {
59
+ return pcap_open_offline(fname, errbuf);
60
+ }
61
+
62
+ int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) {
63
+ if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO)
64
+ return 0;
65
+ return PCAP_ERROR_TSTAMP_PRECISION_NOTSUP;
66
+ }
67
+
68
+ int pcap_get_tstamp_precision(pcap_t *p) {
69
+ return PCAP_TSTAMP_PRECISION_MICRO
70
+ }
71
+
41
72
#ifndef PCAP_TSTAMP_HOST // < v1.2
42
73
43
74
int pcap_set_tstamp_type(pcap_t* p, int t) { return -1; }
@@ -159,12 +190,13 @@ type Handle struct {
159
190
// This must be the first entry to ensure alignment for sync.atomic
160
191
stop uint64
161
192
// cptr is the handle for the actual pcap C object.
162
- cptr * C.pcap_t
163
- timeout time.Duration
164
- device string
165
- deviceIndex int
166
- mu sync.Mutex
167
- closeMu sync.Mutex
193
+ cptr * C.pcap_t
194
+ timeout time.Duration
195
+ device string
196
+ deviceIndex int
197
+ mu sync.Mutex
198
+ closeMu sync.Mutex
199
+ nanoSecsFactor int64
168
200
169
201
// Since pointers to these objects are passed into a C function, if
170
202
// they're declared locally then the Go compiler thinks they may have
@@ -239,7 +271,8 @@ func timeoutMillis(timeout time.Duration) C.int {
239
271
// OpenLive opens a device and returns a *Handle.
240
272
// It takes as arguments the name of the device ("eth0"), the maximum size to
241
273
// read for each packet (snaplen), whether to put the interface in promiscuous
242
- // mode, and a timeout.
274
+ // mode, and a timeout. Warning: this function supports only microsecond timestamps.
275
+ // For nanosecond resolution use an InactiveHandle.
243
276
//
244
277
// See the package documentation for important details regarding 'timeout'.
245
278
func OpenLive (device string , snaplen int32 , promisc bool , timeout time.Duration ) (handle * Handle , _ error ) {
@@ -268,6 +301,7 @@ func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration)
268
301
if p .cptr == nil {
269
302
return nil , errors .New (C .GoString (buf ))
270
303
}
304
+ p .nanoSecsFactor = 1000
271
305
272
306
// Only set the PCAP handle into non-blocking mode if we have a timeout
273
307
// greater than zero. If the user wants to block forever, we'll let libpcap
@@ -282,22 +316,33 @@ func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration)
282
316
return p , nil
283
317
}
284
318
285
- // OpenOffline opens a file and returns its contents as a *Handle.
319
+ // OpenOffline opens a file and returns its contents as a *Handle. Depending on libpcap support and
320
+ // on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
321
+ // internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
322
+ // to query the actual resolution used.
286
323
func OpenOffline (file string ) (handle * Handle , err error ) {
287
324
buf := (* C .char )(C .calloc (errorBufferSize , 1 ))
288
325
defer C .free (unsafe .Pointer (buf ))
289
326
cf := C .CString (file )
290
327
defer C .free (unsafe .Pointer (cf ))
291
328
292
- cptr := C .pcap_open_offline (cf , buf )
329
+ cptr := C .pcap_open_offline_with_tstamp_precision (cf , C . PCAP_TSTAMP_PRECISION_NANO , buf )
293
330
if cptr == nil {
294
331
return nil , errors .New (C .GoString (buf ))
295
332
}
296
333
h := & Handle {cptr : cptr }
334
+ if C .pcap_get_tstamp_precision (cptr ) == C .PCAP_TSTAMP_PRECISION_NANO {
335
+ h .nanoSecsFactor = 1
336
+ } else {
337
+ h .nanoSecsFactor = 1000
338
+ }
297
339
return h , nil
298
340
}
299
341
300
- // OpenOfflineFile returns contents of input file as a *Handle.
342
+ // OpenOfflineFile returns contents of input file as a *Handle. Depending on libpcap support and
343
+ // on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
344
+ // internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
345
+ // to query the actual resolution used.
301
346
func OpenOfflineFile (file * os.File ) (handle * Handle , err error ) {
302
347
return openOfflineFile (file )
303
348
}
@@ -408,7 +453,7 @@ func (p *Handle) getNextBufPtrLocked(ci *gopacket.CaptureInfo) error {
408
453
// got a packet, set capture info and return
409
454
sec := int64 (p .pkthdr .ts .tv_sec )
410
455
// convert micros to nanos
411
- nanos := int64 (p .pkthdr .ts .tv_usec ) * 1000
456
+ nanos := int64 (p .pkthdr .ts .tv_usec ) * p . nanoSecsFactor
412
457
413
458
ci .Timestamp = time .Unix (sec , nanos )
414
459
ci .CaptureLength = int (p .pkthdr .caplen )
@@ -923,6 +968,14 @@ func (p *Handle) SnapLen() int {
923
968
return int (len )
924
969
}
925
970
971
+ // Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution.
972
+ func (p * Handle ) Resolution () gopacket.TimestampResolution {
973
+ if p .nanoSecsFactor == 1 {
974
+ return gopacket .TimestampResolutionMillisecond
975
+ }
976
+ return gopacket .TimestampResolutionNanosecond
977
+ }
978
+
926
979
// TimestampSource tells PCAP which type of timestamp to use for packets.
927
980
type TimestampSource C.int
928
981
@@ -968,6 +1021,8 @@ func (p *InactiveHandle) Error() error {
968
1021
// Activate activates the handle. The current InactiveHandle becomes invalid
969
1022
// and all future function calls on it will fail.
970
1023
func (p * InactiveHandle ) Activate () (* Handle , error ) {
1024
+ // ignore error with set_tstamp_precision, since the actual precision is queried later anyway
1025
+ C .pcap_set_tstamp_precision (p .cptr , C .PCAP_TSTAMP_PRECISION_NANO )
971
1026
err := activateError (C .pcap_activate (p .cptr ))
972
1027
if err != aeNoError {
973
1028
if err == aeWarning {
@@ -981,6 +1036,11 @@ func (p *InactiveHandle) Activate() (*Handle, error) {
981
1036
device : p .device ,
982
1037
deviceIndex : p .deviceIndex ,
983
1038
}
1039
+ if C .pcap_get_tstamp_precision (h .cptr ) == C .PCAP_TSTAMP_PRECISION_NANO {
1040
+ h .nanoSecsFactor = 1
1041
+ } else {
1042
+ h .nanoSecsFactor = 1000
1043
+ }
984
1044
p .cptr = nil
985
1045
return h , nil
986
1046
}
0 commit comments