Blob Blame History Raw
From 9784ac1d98ae256e9e9f1830e7bab3b6bc20ec6c Mon Sep 17 00:00:00 2001
From: Michal Sekletar <sekletar.m@gmail.com>
Date: Wed, 19 Mar 2014 14:14:25 +0100
Subject: [PATCH 1/4] Introduce --time-stamp-precision

A while ago we introduced new API in libpcap which made possible to
request time stamps with higher precision (nanoseconds). This commit
aims to move things forward and implement missing bits. It introduces
new long option --time-stamp-precision. Note that there is no equivalent
short option.

When used for a live capture tcpdump will ask the kernel for time stamp
with desired precision and tcpdump will print fraction part of the time
stamp using respective format. We currently support only microsecond and
nanosecond precision. In the future we might support even more granular
time stamp precision, but we should be fine to support only
microseconds and nanoseconds for now. libpcap doesn't provide anything
else at the moment anyway.

When used in combination with -r/-w options then we obtain time stamps
appropriately scaled up or down from libpcap. Also note that distinct
magic number is used for savefiles containing nanosecond time stamps.

(cherry picked from commit 52b27d11fc50ebc4f1fc54b53fd9437d62dd7f4a)

Conflicts:
        netdissect.h
        tcpdump.c
---
 netdissect.h |  1 +
 tcpdump.1.in |  9 +++++++++
 tcpdump.c    | 41 +++++++++++++++++++++++++++++++++++++++--
 util.c       |  9 ++++++---
 4 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/netdissect.h b/netdissect.h
index 4fd4726..e0146e7 100644
--- a/netdissect.h
+++ b/netdissect.h
@@ -123,6 +123,7 @@ struct netdissect_options {
   time_t ndo_Gflag_time;    /* The last time_t the dump file was rotated. */
   int ndo_Wflag;          /* recycle output files after this number of files */
   int ndo_WflagChars;
+  int ndo_tstamp_precision;   /* requested time stamp precision */
   int ndo_Hflag;		/* dissect 802.11s draft mesh standard */
   int ndo_suppress_default_print; /* don't use default_print() for unknown packet types */
   const char *ndo_dltname;
diff --git a/tcpdump.1.in b/tcpdump.1.in
index a5a0e28..6083474 100644
--- a/tcpdump.1.in
+++ b/tcpdump.1.in
@@ -399,6 +399,15 @@ List the supported time stamp types for the interface and exit.  If the
 time stamp type cannot be set for the interface, no time stamp types are
 listed.
 .TP
+.BI \-\-time\-stamp\-precision= tstamp_precision
+.PD
+Set the time stamp precision for the capture to
+\fItstamp_precision\fP. Currently supported are microseconds and
+nanoseconds. Note that availability of high precision time stamps (nanoseconds)
+and their actual accuracy is platform and HW dependent. Also note that when
+writing captures to the savefile, distinct magic number is used to distinguish
+savefiles which contains time stamps in nanoseconds.
+.TP
 .B \-K
 Don't attempt to verify IP, TCP, or UDP checksums.  This is useful for
 interfaces that perform some or all of those checksum calculation in
diff --git a/tcpdump.c b/tcpdump.c
index 79db6d7..444e1e3 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -73,6 +73,7 @@ extern int SIZE_BUF;
 #include <grp.h>
 #include <errno.h>
 #endif /* WIN32 */
+#include <getopt.h>
 
 /* capabilities convinience library */
 #ifdef HAVE_CAP_NG_H
@@ -529,6 +530,12 @@ show_dlts_and_exit(const char *device, pcap_t *pd)
 #define P_FLAG
 #endif
 
+#define OPTION_TSTAMP_PRECISION 130
+
+static struct option longopts[] = {
+	{ "time-stamp-precision", required_argument, NULL, OPTION_TSTAMP_PRECISION},
+};
+
 #ifndef WIN32
 /* Drop root privileges and chroot if necessary */
 static void
@@ -682,6 +689,18 @@ get_next_file(FILE *VFile, char *ptr)
 	return ret;
 }
 
+static int
+tstamp_precision_from_string(const char *precision)
+{
+	if (strncmp(precision, "nano", strlen("nano")) == 0)
+		return PCAP_TSTAMP_PRECISION_NANO;
+
+	if (strncmp(precision, "micro", strlen("micro")) == 0)
+		return PCAP_TSTAMP_PRECISION_MICRO;
+
+	return -EINVAL;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -747,7 +766,7 @@ main(int argc, char **argv)
 #endif
 
 	while (
-	    (op = getopt(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOp" P_FLAG "qr:Rs:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:")) != -1)
+               (op = getopt_long(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOp" P_FLAG "qr:Rs:StT:u" U_FLAG "vV:w:W:xXy:Yz:Z:", longopts, NULL)) != -1)
 		switch (op) {
 
 		case 'a':
@@ -1128,6 +1147,12 @@ main(int argc, char **argv)
 			}
 			break;
 
+		case OPTION_TSTAMP_PRECISION:
+			gndo->ndo_tstamp_precision = tstamp_precision_from_string(optarg);
+			if (gndo->ndo_tstamp_precision < 0)
+				error("unsupported time stamp precision");
+			break;
+
 		default:
 			usage();
 			/* NOTREACHED */
@@ -1213,7 +1238,12 @@ main(int argc, char **argv)
 			RFileName = VFileLine;
 		}
 
-		pd = pcap_open_offline(RFileName, ebuf);
+                if (gndo->ndo_tstamp_precision == PCAP_TSTAMP_PRECISION_NANO)
+			pd = pcap_open_offline_with_tstamp_precision(RFileName, PCAP_TSTAMP_PRECISION_NANO, ebuf);
+		else
+			pd = pcap_open_offline_with_tstamp_precision(RFileName, PCAP_TSTAMP_PRECISION_MICRO, ebuf);
+
+
 		if (pd == NULL)
 			error("%s", ebuf);
 		dlt = pcap_datalink(pd);
@@ -1262,6 +1292,13 @@ main(int argc, char **argv)
 		if (Jflag)
 			show_tstamp_types_and_exit(device, pd);
 #endif
+                if (gndo->ndo_tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) {
+			status = pcap_set_tstamp_precision(pd, PCAP_TSTAMP_PRECISION_NANO);
+			if (status != 0)
+                                error("%s: Can't set nanosecond time stamp precision: %s",
+                                      device, pcap_statustostr(status));
+                }
+
 		/*
 		 * Is this an interface that supports monitor mode?
 		 */
diff --git a/util.c b/util.c
index a2ef36d..6bc05c0 100644
--- a/util.c
+++ b/util.c
@@ -146,9 +146,12 @@ fn_printzp(register const u_char *s, register u_int n,
 char *
 ts_format(register int sec, register int usec)
 {
-        static char buf[sizeof("00:00:00.000000")];
-        (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06u",
-               sec / 3600, (sec % 3600) / 60, sec % 60, usec);
+	static char buf[sizeof("00:00:00.000000000")];
+	const char *format = gndo->ndo_tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ?
+                "%02d:%02d:%02d.%09u" : "%02d:%02d:%02d.%06u";
+
+	snprintf(buf, sizeof(buf), format,
+                 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
 
         return buf;
 }
-- 
2.4.3