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: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Mon, 30 Aug 1999 01:11:04 -0700
> > 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?)

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"?

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.)