From d49b158b4926ddaf988fe857bb97cb369cb29823 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Sat, 6 Nov 1999 10:31:47 +0000 Subject: [PATCH] Add in a gross heuristic that attempts to detect files with the version of the "libpcap" patch that changes the per-packet header but not the magic number - it seems to work on at least one capture file I tried it on. Give the modified "libpcap" format a WTAP_FILE type of its own (so that, in the future, we could support writing captures out in that format, possibly). svn path=/trunk/; revision=987 --- wiretap/libpcap.c | 195 +++++++++++++++++++++++++++++++++++----------- wiretap/wtap.c | 6 +- wiretap/wtap.h | 9 ++- 3 files changed, 161 insertions(+), 49 deletions(-) diff --git a/wiretap/libpcap.c b/wiretap/libpcap.c index 2580c15066..dcb46b6650 100644 --- a/wiretap/libpcap.c +++ b/wiretap/libpcap.c @@ -1,6 +1,6 @@ /* libpcap.c * - * $Id: libpcap.c,v 1.22 1999/11/06 08:42:00 guy Exp $ + * $Id: libpcap.c,v 1.23 1999/11/06 10:31:47 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -41,17 +41,17 @@ PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC is a byte-swapped version of that. - PCAP_MUTANT_MAGIC is for Alexey Kuznetsov's modified "libpcap" + PCAP_MODIFIED_MAGIC is for Alexey Kuznetsov's modified "libpcap" format, as generated on Linux systems that have a "libpcap" with his patches, at http://ftp.sunet.se/pub/os/Linux/ip-routing/lbl-tools/ - applied; PCAP_SWAPPED_MUTANT_MAGIC is the byte-swapped version. */ + applied; PCAP_SWAPPED_MODIFIED_MAGIC is the byte-swapped version. */ #define PCAP_MAGIC 0xa1b2c3d4 #define PCAP_SWAPPED_MAGIC 0xd4c3b2a1 -#define PCAP_MUTANT_MAGIC 0xa1b2cd34 -#define PCAP_SWAPPED_MUTANT_MAGIC 0x34cdb2a1 +#define PCAP_MODIFIED_MAGIC 0xa1b2cd34 +#define PCAP_SWAPPED_MODIFIED_MAGIC 0x34cdb2a1 /* Macros to byte-swap 32-bit and 16-bit quantities. */ #define BSWAP32(x) \ @@ -87,7 +87,7 @@ struct pcaprec_hdr { }; /* "libpcap" record header for Alexey's patched version. */ -struct pcaprec_mutant_hdr { +struct pcaprec_modified_hdr { struct pcaprec_hdr hdr; /* the regular header */ guint32 ifindex; /* index, in *capturing* machine's list of interfaces, of the interface on which this @@ -97,6 +97,7 @@ struct pcaprec_mutant_hdr { }; static int libpcap_read(wtap *wth, int *err); +static void adjust_header(wtap *wth, struct pcaprec_hdr *hdr); static int libpcap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, const u_char *pd, int *err); static int libpcap_dump_close(wtap_dumper *wdh, int *err); @@ -164,8 +165,10 @@ int libpcap_open(wtap *wth, int *err) int bytes_read; guint32 magic; struct pcap_hdr hdr; - gboolean byte_swapped = FALSE; - gboolean mutant = FALSE; + gboolean byte_swapped; + gboolean modified; + struct pcaprec_hdr first_rec_hdr; + struct pcaprec_hdr second_rec_hdr; /* Read in the number that should be at the start of a "libpcap" file */ file_seek(wth->fh, 0, SEEK_SET); @@ -185,28 +188,28 @@ int libpcap_open(wtap *wth, int *err) case PCAP_MAGIC: /* Host that wrote it has our byte order. */ byte_swapped = FALSE; - mutant = FALSE; + modified = FALSE; break; - case PCAP_MUTANT_MAGIC: + case PCAP_MODIFIED_MAGIC: /* Host that wrote it has our byte order, but was running a program using the patched "libpcap". */ byte_swapped = FALSE; - mutant = TRUE; + modified = TRUE; break; case PCAP_SWAPPED_MAGIC: /* Host that wrote it has a byte order opposite to ours. */ byte_swapped = TRUE; - mutant = FALSE; + modified = FALSE; break; - case PCAP_SWAPPED_MUTANT_MAGIC: + case PCAP_SWAPPED_MODIFIED_MAGIC: /* Host that wrote it out has a byte order opposite to ours, and was running a program using the patched "libpcap". */ byte_swapped = TRUE; - mutant = TRUE; + modified = TRUE; break; default: @@ -248,15 +251,112 @@ int libpcap_open(wtap *wth, int *err) } /* This is a libpcap file */ - wth->file_type = WTAP_FILE_PCAP; + wth->file_type = modified ? WTAP_FILE_PCAP_MODIFIED : WTAP_FILE_PCAP; wth->capture.pcap = g_malloc(sizeof(libpcap_t)); wth->capture.pcap->byte_swapped = byte_swapped; - wth->capture.pcap->mutant = mutant; + wth->capture.pcap->modified = modified; wth->capture.pcap->version_major = hdr.version_major; wth->capture.pcap->version_minor = hdr.version_minor; wth->subtype_read = libpcap_read; wth->file_encap = pcap_encap[hdr.network]; wth->snapshot_length = hdr.snaplen; + + /* + * Is this a capture file with the non-modified magic number? + */ + if (!wth->capture.pcap->modified) { + /* + * Yes. Let's look at the header for the first record, + * and see if, interpreting it as a non-modified header, + * the position where it says the header for the + * *second* record is contains a corrupted header. + * + * If so, this may be a modified capture file with a + * non-modified magic number - in some versions of + * Alexey's patches, the packet header format was + * changed but the magic number wasn't, and, alas, + * Red Hat appear to have picked up one of those + * patches for RH 6.1, meaning RH 6.1 has a "tcpdump" + * that writes out files that can't be read by any software + * that expects non-modified headers if the magic number isn't + * the modified magic number (e.g., any normal version of + * "tcpdump", and Ethereal if we don't do this gross + * heuristic). + */ + bytes_read = file_read(&first_rec_hdr, 1, + sizeof first_rec_hdr, wth->fh); + if (bytes_read != sizeof first_rec_hdr) { + *err = file_error(wth->fh); + if (*err != 0) + return -1; /* failed to read it */ + + /* + * Short read - assume the file isn't modified, + * and put the seek pointer back. The attempt + * to read the first packet will presumably get + * the same short read. + */ + goto give_up; + } + + adjust_header(wth, &first_rec_hdr); + + if (first_rec_hdr.incl_len > WTAP_MAX_PACKET_SIZE) { + /* + * The first record is bogus, so this is probably + * a corrupt file. Assume the file isn't modified, + * and put the seek pointer back. The attempt + * to read the first packet will probably get + * the same bogus length. + */ + goto give_up; + } + + file_seek(wth->fh, + wth->data_offset + sizeof first_rec_hdr + first_rec_hdr.incl_len, + SEEK_SET); + bytes_read = file_read(&second_rec_hdr, 1, + sizeof second_rec_hdr, wth->fh); + + /* + * OK, does the next packet's header look sane? + */ + if (bytes_read != sizeof second_rec_hdr) { + *err = file_error(wth->fh); + if (*err != 0) + return -1; /* failed to read it */ + + /* + * Short read - assume the file isn't modified, + * and put the seek pointer back. The attempt + * to read the second packet will presumably get + * the same short read error. + */ + goto give_up; + } + + adjust_header(wth, &second_rec_hdr); + if (second_rec_hdr.incl_len > WTAP_MAX_PACKET_SIZE) { + /* + * Oh, dear. Maybe it's a Capture File + * From Hell, and what looks like the + * "header" of the next packet is actually + * random junk from the middle of a packet. + * Try treating it as a modified file; + * if that doesn't work, it probably *is* + * a corrupt file. + */ + wth->file_type = WTAP_FILE_PCAP_MODIFIED; + wth->capture.pcap->modified = TRUE; + } + + give_up: + /* + * Restore the seek pointer. + */ + file_seek(wth->fh, wth->data_offset, SEEK_SET); + } + return 1; } @@ -265,12 +365,13 @@ static int libpcap_read(wtap *wth, int *err) { guint packet_size; int bytes_to_read, bytes_read; - struct pcaprec_mutant_hdr hdr; + struct pcaprec_modified_hdr hdr; int data_offset; /* Read record header. */ errno = WTAP_ERR_CANT_READ; - bytes_to_read = wth->capture.pcap->mutant ? sizeof hdr : sizeof hdr.hdr; + bytes_to_read = wth->capture.pcap->modified ? + sizeof hdr : sizeof hdr.hdr; bytes_read = file_read(&hdr, 1, bytes_to_read, wth->fh); if (bytes_read != bytes_to_read) { *err = file_error(wth->fh); @@ -284,32 +385,7 @@ static int libpcap_read(wtap *wth, int *err) } wth->data_offset += bytes_read; - if (wth->capture.pcap->byte_swapped) { - /* Byte-swap the record header fields. */ - hdr.hdr.ts_sec = BSWAP32(hdr.hdr.ts_sec); - hdr.hdr.ts_usec = BSWAP32(hdr.hdr.ts_usec); - hdr.hdr.incl_len = BSWAP32(hdr.hdr.incl_len); - hdr.hdr.orig_len = BSWAP32(hdr.hdr.orig_len); - } - - /* In file format version 2.3, the "incl_len" and "orig_len" fields - were swapped, in order to match the BPF header layout. - - Unfortunately, some files were, according to a comment in the - "libpcap" source, written with version 2.3 in their headers - but without the interchanged fields, so if "incl_len" is - greater than "orig_len" - which would make no sense - we - assume that we need to swap them. */ - if (wth->capture.pcap->version_major == 2 && - (wth->capture.pcap->version_minor < 3 || - (wth->capture.pcap->version_minor == 3 && - hdr.hdr.incl_len > hdr.hdr.orig_len))) { - guint32 temp; - - temp = hdr.hdr.orig_len; - hdr.hdr.orig_len = hdr.hdr.incl_len; - hdr.hdr.incl_len = temp; - } + adjust_header(wth, &hdr.hdr); packet_size = hdr.hdr.incl_len; if (packet_size > WTAP_MAX_PACKET_SIZE) { @@ -346,6 +422,37 @@ static int libpcap_read(wtap *wth, int *err) return data_offset; } +static void +adjust_header(wtap *wth, struct pcaprec_hdr *hdr) +{ + if (wth->capture.pcap->byte_swapped) { + /* Byte-swap the record header fields. */ + hdr->ts_sec = BSWAP32(hdr->ts_sec); + hdr->ts_usec = BSWAP32(hdr->ts_usec); + hdr->incl_len = BSWAP32(hdr->incl_len); + hdr->orig_len = BSWAP32(hdr->orig_len); + } + + /* In file format version 2.3, the "incl_len" and "orig_len" fields + were swapped, in order to match the BPF header layout. + + Unfortunately, some files were, according to a comment in the + "libpcap" source, written with version 2.3 in their headers + but without the interchanged fields, so if "incl_len" is + greater than "orig_len" - which would make no sense - we + assume that we need to swap them. */ + if (wth->capture.pcap->version_major == 2 && + (wth->capture.pcap->version_minor < 3 || + (wth->capture.pcap->version_minor == 3 && + hdr->incl_len > hdr->orig_len))) { + guint32 temp; + + temp = hdr->orig_len; + hdr->orig_len = hdr->incl_len; + hdr->incl_len = temp; + } +} + int wtap_pcap_encap_to_wtap_encap(int encap) { if (encap < 0 || encap >= NUM_PCAP_ENCAPS) diff --git a/wiretap/wtap.c b/wiretap/wtap.c index fd0de940c0..6954feb92b 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -1,6 +1,6 @@ /* wtap.c * - * $Id: wtap.c,v 1.27 1999/10/31 17:46:10 gram Exp $ + * $Id: wtap.c,v 1.28 1999/11/06 10:31:45 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -66,6 +66,9 @@ const char *wtap_file_type_string(wtap *wth) case WTAP_FILE_PCAP: return "pcap"; + case WTAP_FILE_PCAP_MODIFIED: + return "pcap-modified"; + case WTAP_FILE_LANALYZER: return "Novell LANalyzer"; @@ -161,6 +164,7 @@ void wtap_close(wtap *wth) * But for now this will work. */ switch(wth->file_type) { case WTAP_FILE_PCAP: + case WTAP_FILE_PCAP_MODIFIED: g_free(wth->capture.pcap); break; diff --git a/wiretap/wtap.h b/wiretap/wtap.h index bf1471a8b8..269be246c0 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -1,6 +1,6 @@ /* wtap.h * - * $Id: wtap.h,v 1.47 1999/11/06 08:42:01 guy Exp $ + * $Id: wtap.h,v 1.48 1999/11/06 10:31:46 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -101,8 +101,9 @@ #define WTAP_FILE_UNKNOWN 0 #define WTAP_FILE_WTAP 1 #define WTAP_FILE_PCAP 2 -#define WTAP_FILE_LANALYZER 3 -#define WTAP_FILE_NGSNIFFER 4 +#define WTAP_FILE_PCAP_MODIFIED 3 +#define WTAP_FILE_LANALYZER 4 +#define WTAP_FILE_NGSNIFFER 5 #define WTAP_FILE_SNOOP 6 #define WTAP_FILE_IPTRACE 7 #define WTAP_FILE_NETMON_1_x 8 @@ -160,7 +161,7 @@ typedef struct { typedef struct { gboolean byte_swapped; - gboolean mutant; + gboolean modified; guint16 version_major; guint16 version_minor; } libpcap_t;