Ethereal-dev: Re: [ethereal-dev] 64-bit pcap timestamp problems

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: John Heffner <heffner@xxxxxxx>
Date: Mon, 30 Aug 1999 12:03:14 -0400 (EDT)
On Mon, 30 Aug 1999, Guy Harris wrote:

> > > This makes sense; however, every application that uses libpcap must be
> > > careful to define its own timeval structure that has 32-bit ints, instead
> > > of using the one defined in the system headers.
> > 
> > ...or "libpcap" needs to be changed not to use "struct timeval" in
> > "pcap_pkthdr", and to use instead, say, "bpf_u_int32 ts_sec" and
> > "bpf_u_int32 ts_usec", and the applications need to refer to "ts_sec"
> > and "ts_usec" rather than "ts.tv_sec" and "ts.tv_usec".
> 
> ...which won't fix the problem.
> 
> Unfortunately, as you note, having the "libpcap" packet header start
> with anything other than a "struct timeval" breaks "libpcap" programs -
> "tcpdump", for example, prints timestamps with
> 
> 	ts_print(&h->ts);
> 
> where "h" is a "const struct pcap_pkthdr *".
> 
> How does "pcap.h" define "struct pcap_pkthdr" on RedHat 5.2 and 6.0 on
> Alpha?  (Does it define it any differently on other platforms?)

AFAIK, libpcap sources are exactly the same for Linux/Alpha as for
Linux/i386.

> In your original mail, you said:
> 
> > I'm running linux-2.2.10, redhat-5.2 on an alpha.  With the 2.2-series
> > kernel on alpha, the seconds and microseconds are stored as 64-bit
> > integers instead of 32-bit integers.  This is a nasty little problem I ran
> > into with the stock tcpdump/libpcap in the stock redhat-5.2/alpha (glibc
> > 2.0). The headers that come with redhat define a timestamp as two 32-bit
> > ints, and this causes all sorts of nastyness.  I got it to work by
> > building libpcap/tcpdump after changing the struct timeval in timebits.h
> > to look like the one in the kernel.  I beleive RedHat have made this same
> > change as of 6.0 (glibc 2.1).
> 
> What is "timebits.h"?  A generic header used in userland (e.g., included
> by <sys/time.h>), or something specific to 'libpcap"?

timebits.h is indeed a generic header in userland included by
<sys/time.h>.

> If 6.0 (and other 64-bit Linux distributions with 2.2-series kernels)
> declare a "struct pcap_pkthdr" as
> 
> 	struct pcap_pkthdr {
> 		struct timeval ts;	/* time stamp */
> 		bpf_u_int32 caplen;	/* length of portion present */
> 		bpf_u_int32 len;	/* length this packet (off wire) */
> 	};
> 
> with "struct timeval" having 64-bit "tv_sec" and "tv_usec", we probably
> need to do the same in Wiretap.
> 
> > struct pcaprec_hdr maybe should be changed to use a struct timeval
> > as defined in timebits.h, like libpcap does.  There's a big problem with
> > this, though -- traces on 64-bit machines won't be viewable on 32-bit
> > machines and vica versa.  This seems like a problem with libpcap.
> 
> Actually, if the "if" right above this is true, we *can* arrange to read
> traces from 64-bit machines on 32-bit machines, and *vice versa*....
> 
> A 32-bit-time-stamp "libpcap" packet header looks like (all lines
> represent 32-bit quantities):
> 
> 	tv_sec
> 	tv_usec
> 	caplen
> 	len
> 
> A 64-bit-time-stamp big-endian "libpcap" packet header looks like:
> 
> 	upper 32 bits of "tv_sec" (probably 0)
> 	lower 32 bits of "tv_sec"
> 	upper 32 bits of "tv_usec", which should be 0 (tv_usec < 1000000)
> 	lower 32 bits of "tv_usec"
> 	caplen
> 	len
> 
> A 64-bit-time-stamp little-endian header looks like:
> 
> 	lower 32 bits of "tv_sec"
> 	upper 32 bits of "tv_sec" (probably 0)
> 	lower 32 bits of "tv_usec"
> 	upper 32 bits of "tv_usec", which should be 0 (tv_usec < 1000000)
> 	caplen
> 	len
> 
> If you read the first 4 32-bit words of the packet header, and it's from
> a machine with 32-bit time stamps, the third and fourth 32-bit words
> should be non-zero, as one is the captured length and one is the
> on-the-wire length.
> 
> If it's from a big-endian machine with 64-bit time stamps, however, the
> third word should be zero, as "tv_usec" should be less than 1 000 000,
> and thus should fit in 32 bits.  If it's from a little-endian machine
> with 64-bit time stamps, the fourth word should be zero, for the same
> reason.
> 
> So, if we keep a flag saying "32-bit timestamps, 64-bit timestamps, or
> as-yet-unknown time stamp size", start it out as "as yet unknown", and:
> 
> 	if it's "as yet unknown", read the first 4 32-bit words of the
> 	header into a structure with 32-bit time stamps and check
> 	whether either "len" or "caplen" are zero - if so, flag it as
> 	"64-bit", copy those 4 words to a structure with 64-bit time
> 	stamps, and read the next 2 32-bit words into the fifth and
> 	sixth words of that structure;
> 
> 	if it's "32 bits", read 4 32-bit words into a 32-bit time stamp
> 	structure;
> 
> 	if it's "64 bits", read 6 32-bit words into a 64-bit time stamp
> 	structure;
> 
> and then process the appropriate structure, we can handle either time
> stamp size on both 32-bit and 64-bit machines.
> 
> A similar hack could be put into "libpcap" itself, so that, at least if
> you have such a hacked "libpcap", programs using "libpcap" to read
> capture files could read capture files both from machines with 32-bit
> time stamps and from machines with 64-bit time stamps.
> 
> (When reading a *live* capture, it'd treat it as having the native time
> stamp type.)

Well, as pointed out before, any change to the libpcap file format would
break lots of stuff.  I don't know how possible backwards compatibility
would be.  This seems like an issue for the LBL folks.

  -John