Skip to content

Commit

Permalink
Bug #863: implement tcpr_pcap_open() universally
Browse files Browse the repository at this point in the history
Add macros that can properly convert between PCAP timestamps and timespec/timeval.

We still use pcap_open_offline() for tcprewrite.c, otherwise tests fail because timestamps get written inconsistently across libpcap versions.

Also fix multiplier calculation error.
  • Loading branch information
fklassen committed Jun 3, 2024
1 parent c7d7ff0 commit 1f648d6
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 23 deletions.
5 changes: 5 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,11 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[

if test $have_pcap_open_offline_with_tstamp_precision = yes ; then
AC_DEFINE([HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION], [1], [Does libpcap have pcap_open_offline_with_tstamp_precision?])
AC_DEFINE([PCAP_TSTAMP_US_TO_NS_MULTIPLIER], [1], [Multiplier for conversion from PCAP usec to nsec])
AC_DEFINE([PCAP_TSTAMP_US_TO_US_DIVISOR], [1000], [Divisor for conversion from PCAP usec to usec])
else
AC_DEFINE([PCAP_TSTAMP_US_TO_NS_MULTIPLIER], [1000], [Multiplier for conversion from PCAP usec to nsec])
AC_DEFINE([PCAP_TSTAMP_US_TO_US_DIVISOR], [1], [Divisor for conversion from PCAP usec to usec])
fi


Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
06/01/2024 Version 4.5.0-beta1
- fix nansecond timestamp regression bug (#863)
- --fixhdrlen option added to control action on packet length changes (#846)
- incorrect checksum for certain IPv4 packets - fixed by #846 (#844)
- add check for IPv6 extension header length (#827 #842)
Expand Down
3 changes: 2 additions & 1 deletion src/common/fakepcapnav.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "defines.h"

Check failure on line 26 in src/common/fakepcapnav.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/fakepcapnav.c:26:10 [clang-diagnostic-error]

'defines.h' file not found
#include "config.h"
#include "common.h"
#include "utils.h"
#include <stdlib.h>

#ifndef HAVE_PCAPNAV
Expand All @@ -52,7 +53,7 @@ pcapnav_open_offline(const char *filename)
err(-1, "malloc() error: unable to malloc pcapnav_t");
}

pcapnav->pcap = pcap_open_offline(filename, errbuf);
pcapnav->pcap = tcpr_pcap_open(filename, errbuf);
if (pcapnav->pcap == NULL) {
errx(-1, "Error opening pcap file %s: %s", filename, errbuf);
}
Expand Down
2 changes: 1 addition & 1 deletion src/common/tcpdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ tcpdump_print(tcpdump_t *tcpdump, struct pcap_pkthdr *pkthdr, const u_char *data

/* convert header to file-format packet header */
actual_pkthdr.ts.ts_sec = (uint32_t)pkthdr->ts.tv_sec;
actual_pkthdr.ts.ts_usec = (uint32_t)pkthdr->ts.tv_sec;
actual_pkthdr.ts.ts_usec = (uint32_t)(pkthdr->ts.tv_usec / PCAP_TSTAMP_US_TO_US_DIVISOR);
actual_pkthdr.caplen = pkthdr->caplen;
actual_pkthdr.len = pkthdr->len;

Expand Down
11 changes: 11 additions & 0 deletions src/common/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ our_safe_strdup(const char *str, const char *funcname, int line, const char *fil
return newstr;
}

pcap_t*
tcpr_pcap_open(const char *path, char *ebuf)
{
#ifdef HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION
return pcap_open_offline_with_tstamp_precision(path, PCAP_TSTAMP_PRECISION_NANO, ebuf);
#else
return pcap_open_offline(path, ebuf);

Check warning on line 106 in src/common/utils.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/utils.c:106:12 [performance-no-int-to-ptr]

integer to pointer cast pessimizes optimization opportunities
#endif
}


/**
* calls free and sets to NULL.
*/
Expand Down
1 change: 1 addition & 0 deletions src/common/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ void packet_stats(const tcpreplay_stats_t *stats);
int format_date_time(struct timespec *when, char *buf, size_t len);
uint32_t tcpr_random(uint32_t *seed);
void restore_stdin(void);
pcap_t* tcpr_pcap_open(const char *path, char *ebuf);

/* our "safe" implimentations of functions which allocate memory */
#define safe_malloc(x) our_safe_malloc(x, __FUNCTION__, __LINE__, __FILE__)
Expand Down
22 changes: 16 additions & 6 deletions src/defines.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -359,14 +359,24 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t typedef u_int32_t uint32_t
(a)->tv_nsec = (b)->tv_nsec; \
} while (0)

/* libpcap puts nanosec values in tv_usec when pcap file is read with nanosec precision*/
#define TIMEVAL_AS_TIMESPEC_SET(a, b) \
do { \
(a)->tv_sec = (b)->tv_sec; \
(a)->tv_nsec = (b)->tv_usec * 1000; \
/* libpcap that supports it, puts nanosecond values in tv_usec when pcap file is read with nanosec precision,
* and so tv_usec is directly copied to tv_nsec.
* But older versions do that do not support nanosecond precision need to multiply tv_usec by 1000 to convert
* to tv_nsec.
*/
#define PCAP_TIMEVAL_TO_TIMESPEC_SET(a, b) \
do { \
(b)->tv_sec = (a)->tv_sec; \
(b)->tv_nsec = (a)->tv_usec * PCAP_TSTAMP_US_TO_NS_MULTIPLIER; \
} while(0)

#define PCAP_TIMEVAL_TO_TIMEVAL_SET(a, b) \
do { \
(b)->tv_sec = (a)->tv_sec; \
(b)->tv_usec = (a)->tv_usec / PCAP_TSTAMP_US_TO_US_DIVISOR; \
} while(0)

/*
/*
* Help suppress some compiler warnings
* No problem if variable is actually used
*/
Expand Down
10 changes: 0 additions & 10 deletions src/replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,6 @@ tcpr_replay_index(tcpreplay_t *ctx)
return rcode;
}

static pcap_t *
tcpr_pcap_open(const char *path, char *ebuf)
{
#ifdef HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION
return pcap_open_offline_with_tstamp_precision(path, PCAP_TSTAMP_PRECISION_NANO, ebuf);
#else
return pcap_open_offline(path, ebuf);
#endif
}

/**
* \brief replay a pcap file out interface(s)
*
Expand Down
8 changes: 4 additions & 4 deletions src/send_packets.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ preload_pcap_file(tcpreplay_t *ctx, int idx)
if (close(1) == -1)
warnx("unable to close stdin: %s", strerror(errno));

if ((pcap = pcap_open_offline(path, ebuf)) == NULL)
if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL)

Check warning on line 302 in src/send_packets.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/send_packets.c:302:53 [readability-braces-around-statements]

statement should be inside braces
errx(-1, "Error opening pcap file: %s", ebuf);

dlt = pcap_datalink(pcap);
Expand Down Expand Up @@ -388,7 +388,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
while (!ctx->abort && read_next_packet &&
(pktdata = get_next_packet(options, pcap, &pkthdr, idx, prev_packet)) != NULL) {
struct timespec pkthdr_ts;
TIMEVAL_AS_TIMESPEC_SET(&pkthdr_ts, &pkthdr.ts); // libpcap puts nanosec values in tv_usec
PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr.ts, &pkthdr_ts);
now_is_now = false;
packetnum++;
#if defined TCPREPLAY || defined TCPREPLAY_EDIT
Expand Down Expand Up @@ -739,9 +739,9 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *

if (options->speed.mode == speed_multiplier) {
struct timespec pkthdr_ts;
TIMEVAL_TO_TIMESPEC(&pkthdr_ptr->ts, &pkthdr_ts);
PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr_ptr->ts, &pkthdr_ts);
if (!timesisset(&last_pkt_ts)) {
TIMEVAL_TO_TIMESPEC(&pkthdr_ptr->ts, &last_pkt_ts);
PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr_ptr->ts, &last_pkt_ts);
} else if (timescmp(&pkthdr_ts, &last_pkt_ts, >)) {
struct timespec delta;

Expand Down
2 changes: 1 addition & 1 deletion src/tcpprep.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ main(int argc, char *argv[])

readpcap:
/* open the pcap file */
if ((options->pcap = pcap_open_offline(OPT_ARG(PCAP), errbuf)) == NULL) {
if ((options->pcap = tcpr_pcap_open(OPT_ARG(PCAP), errbuf)) == NULL) {
close(out_file);
tcpprep_close(tcpprep);
errx(-1, "Error opening libpcap: %s", errbuf);
Expand Down

0 comments on commit 1f648d6

Please sign in to comment.