Ethereal-dev: [Ethereal-dev] PATCH: ethereal file reader

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

From: Daniel Thompson <d.thompson@xxxxxxx>
Date: 22 Feb 2001 20:40:17 +0000
Hi Folks.

Attached is a patch to provide limited etherpeek file format support to
ethereal. It provides read only support for macintosh formats V5, 6 & 7.
If you are happy with its quality please commit it to CVS at this point
(the patch is for 0.8.15 - let me know if it does not apply cleanly to
the wavefront).

Note that this code has not been heavily tested as I do not have very
many packet captures to test it with (one V7 file in fact). If anyone
has any etherpeek captures lying around then let me know, I don't like
providing such sparsely tested code but ...

    Cheers

    Daniel
    --xx--

-- 
Daniel Thompson (Merlin) <d.thompson@xxxxxxx>

How many dull people does it take to change a light bulb?    One.
diff -Naur ethereal-0.8.15/wiretap/Makefile.am ethereal/wiretap/Makefile.am
--- ethereal-0.8.15/wiretap/Makefile.am	Tue Sep 19 18:22:09 2000
+++ ethereal/wiretap/Makefile.am	Sat Feb  3 09:41:23 2001
@@ -42,6 +42,8 @@
 	buffer.h		\
 	csids.c			\
 	csids.h			\
+	etherpeek.c             \
+	etherpeek.h             \
 	file.c			\
 	file_wrappers.c		\
 	file_wrappers.h		\
diff -Naur ethereal-0.8.15/wiretap/etherpeek.c ethereal/wiretap/etherpeek.c
--- ethereal-0.8.15/wiretap/etherpeek.c	Thu Jan  1 01:00:00 1970
+++ ethereal/wiretap/etherpeek.c	Thu Feb 22 20:19:56 2001
@@ -0,0 +1,314 @@
+/* etherpeek.c
+ * Routines for opening etherpeek files
+ * Copyright (c) 2001, Daniel Thompson <d.thompson@xxxxxxx>
+ *
+ * $Id: $
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@xxxxxxxxxx>
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <errno.h>
+#include <string.h>
+#include "wtap-int.h"
+#include "file_wrappers.h"
+#include "buffer.h"
+#include "snoop.h"
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+/* CREDITS
+ *
+ * This file decoder could not have been writen without examining how
+ * tcptrace (http://www.tcptrace.org/) handles etherpeek files.
+ */
+
+/* master header */
+typedef struct etherpeek_master_header {
+	guint8  version;
+	guint8  status;
+} etherpeek_master_header_t;
+#define ETHERPEEK_MASTER_HDR_SIZE 2
+
+/* secondary header (Mac V5,V6,V7) */
+typedef struct etherpeek_m567_header {
+	guint32 filelength;
+	guint32 numPackets;
+	guint32 timeDate;
+	guint32 timeStart;
+	guint32 timeStop;
+	guint32 reserved[7];
+} etherpeek_m567_header_t;
+#define ETHERPEEK_M567_HDR_SIZE 48
+
+/* full header */
+typedef struct etherpeek_header {
+	etherpeek_master_header_t master;
+	union {
+		etherpeek_m567_header_t m567;
+	} secondary;
+} etherpeek_header_t;
+
+/* packet header (Mac V5, V6) */
+typedef struct etherpeek_m56_packet {
+	guint16 length;
+	guint16 sliceLength;
+	guint8  flags;
+	guint8  status;
+	guint32 timestamp;
+	guint16 destNum;
+	guint16 srcNum;
+	guint16 protoNum;
+	char    protoStr[8];
+} etherpeek_m56_packet_t;
+#define ETHERPEEK_M56_PKT_SIZE 24
+
+/* 64-bit time in micro seconds from the (Mac) epoch */
+typedef struct etherpeek_utime {
+	guint32 upper;
+	guint32 lower;
+} etherpeek_utime;
+
+/* packet header (Mac V7) */
+typedef struct etherpeek_m7_packet {
+	guint16 protoNum;
+	guint16 length;
+	guint16 sliceLength;
+	guint8  flags;
+	guint8  status;
+	etherpeek_utime
+	        timestamp;
+} etherpeek_m7_packet_t;
+#define ETHERPEEK_M7_PKT_SIZE 16
+
+typedef struct etherpeek_encap_lookup {
+	guint16 protoNum;
+	int     encap;
+} etherpeek_encap_lookup_t;
+
+static const unsigned int mac2unix = 2082844800u;
+static const etherpeek_encap_lookup_t etherpeek_encap[] = {
+	{ 1400, WTAP_ENCAP_ETHERNET }
+};
+#define NUM_ETHERPEEK_ENCAPS \
+	(sizeof (etherpeek_encap) / sizeof (etherpeek_encap[0]))
+
+static gboolean etherpeek_read_m7(wtap *wth, int *err, int *data_offset);
+static gboolean etherpeek_read_m56(wtap *wth, int *err, int *data_offset);
+
+int etherpeek_open(wtap *wth, int *err)
+{
+	etherpeek_header_t ep_hdr;
+
+	/* etherpeek files to not start with a magic value large enough
+	 * to be unique hence we use the following algorithm to determine
+	 * the type of an unknown file
+	 *  - populate the master header and reject file if there is no match
+	 *  - populate the secondary header and check that the reserved space
+	 *      is zero; there is an obvious flaw here so this algorithm will
+	 *      probably need to be revisiting when improving etherpeek
+	 *      support
+	 */
+	
+	file_seek(wth->fh, 0, SEEK_SET);
+	wth->data_offset = 0;
+
+	g_assert(sizeof(ep_hdr.master) == ETHERPEEK_MASTER_HDR_SIZE);
+	wtap_file_read_unknown_bytes(
+		&ep_hdr.master, sizeof(ep_hdr.master), wth->fh, err);
+	wth->data_offset += sizeof(ep_hdr.master);
+
+	/* switch on the file version */
+	switch (ep_hdr.master.version) {
+		case 5:
+		case 6:
+		case 7:
+			/* get the secondary header */
+			g_assert(sizeof(ep_hdr.secondary.m567) ==
+			        ETHERPEEK_M567_HDR_SIZE);
+			wtap_file_read_unknown_bytes(
+				&ep_hdr.secondary.m567,
+				sizeof(ep_hdr.secondary.m567), wth->fh, err);
+			wth->data_offset += sizeof(ep_hdr.secondary.m567);
+			
+			if ((0 != ep_hdr.secondary.m567.reserved[0]) ||
+			    (0 != ep_hdr.secondary.m567.reserved[1]) ||
+			    (0 != ep_hdr.secondary.m567.reserved[2]) ||
+			    (0 != ep_hdr.secondary.m567.reserved[3])) {
+				/* still unknown */
+				return 0;
+			}
+
+			/* we have a match for a Mac V5, V6 or V7,
+			 * so it is worth preforming byte swaps
+			 */
+			ep_hdr.secondary.m567.filelength =
+				ntohl(ep_hdr.secondary.m567.filelength);
+			ep_hdr.secondary.m567.numPackets =
+				ntohl(ep_hdr.secondary.m567.numPackets);
+			ep_hdr.secondary.m567.timeDate =
+				ntohl(ep_hdr.secondary.m567.timeDate);
+			ep_hdr.secondary.m567.timeStart =
+				ntohl(ep_hdr.secondary.m567.timeStart);
+			ep_hdr.secondary.m567.timeStop =
+				ntohl(ep_hdr.secondary.m567.timeStop);
+
+			/* populate the pseudo header */
+			wth->pseudo_header.etherpeek.reference_time.tv_sec  =
+				ep_hdr.secondary.m567.timeDate - mac2unix;
+			wth->pseudo_header.etherpeek.reference_time.tv_usec =
+				0;
+			break;
+		default:
+			return 0;
+	}
+
+	/* at this point we have recognised the file type and have populated
+	 * the whole ep_hdr structure in host byte order
+	 */
+	
+	switch (ep_hdr.master.version) {
+		case 5:
+		case 6:
+			wth->file_type = WTAP_FILE_ETHERPEEK_MAC_V56;
+			wth->subtype_read = etherpeek_read_m56;
+			wth->subtype_seek_read = wtap_def_seek_read;
+			break;
+		case 7:
+			wth->file_type = WTAP_FILE_ETHERPEEK_MAC_V7;
+			wth->subtype_read = etherpeek_read_m7;
+			wth->subtype_seek_read = wtap_def_seek_read;
+			break;
+		default:
+			/* this is impossible */
+			g_assert_not_reached();
+	};
+
+	wth->file_encap	       = WTAP_ENCAP_PER_PACKET;
+	wth->snapshot_length   = 16384; /* just guessing */
+
+	return 1;
+}
+
+static gboolean etherpeek_read_m7(wtap *wth, int *err, int *data_offset)
+{
+	etherpeek_m7_packet_t ep_pkt;
+	double  t;
+	int i;
+
+	g_assert(sizeof(ep_pkt) == ETHERPEEK_M7_PKT_SIZE);
+	wtap_file_read_expected_bytes(&ep_pkt, sizeof(ep_pkt), wth->fh, err);
+	wth->data_offset += sizeof(ep_pkt);
+
+	/* byte swaps */
+	ep_pkt.protoNum = ntohs(ep_pkt.protoNum);
+	ep_pkt.length = ntohs(ep_pkt.length);
+	ep_pkt.sliceLength = ntohs(ep_pkt.sliceLength);
+	ep_pkt.timestamp.upper = ntohl(ep_pkt.timestamp.upper);
+	ep_pkt.timestamp.lower = ntohl(ep_pkt.timestamp.lower);
+
+	/* force sliceLength to be the actual length of the packet */
+	if (0 == ep_pkt.sliceLength) {
+		ep_pkt.sliceLength = ep_pkt.length;
+	}
+
+	/* test for corrupt data */
+	if (ep_pkt.sliceLength > WTAP_MAX_PACKET_SIZE) {
+		*err = WTAP_ERR_BAD_RECORD;
+		return FALSE;
+	}
+
+	*data_offset = wth->data_offset;
+
+	/* read the frame data */
+	buffer_assure_space(wth->frame_buffer, ep_pkt.sliceLength);
+	wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer),
+	                              ep_pkt.sliceLength, wth->fh, err);
+	wth->data_offset += ep_pkt.sliceLength;
+	
+	/* fill in packet header values */
+	wth->phdr.len    = ep_pkt.length;
+	wth->phdr.caplen = ep_pkt.sliceLength;
+	
+	t =  (double) ep_pkt.timestamp.lower +
+	     (double) ep_pkt.timestamp.upper * 4294967296.0;
+	t -= (double) mac2unix * 1000000.0;
+	wth->phdr.ts.tv_sec  = (time_t)  (t/1000000.0);
+	wth->phdr.ts.tv_usec = (guint32) (t - (double) wth->phdr.ts.tv_sec *
+	                                               1000000.0);
+	wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
+	for (i=0; i<NUM_ETHERPEEK_ENCAPS; i++) {
+		if (etherpeek_encap[i].protoNum == ep_pkt.protoNum) {
+			wth->phdr.pkt_encap = etherpeek_encap[i].encap;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean etherpeek_read_m56(wtap *wth, int *err, int *data_offset)
+{
+	etherpeek_m56_packet_t ep_pkt;
+	int i;
+
+	g_assert(sizeof(ep_pkt) == ETHERPEEK_M56_PKT_SIZE);
+	wtap_file_read_expected_bytes(&ep_pkt, sizeof(ep_pkt), wth->fh, err);
+	wth->data_offset += sizeof(ep_pkt);
+
+	/* byte swaps */
+	ep_pkt.length = ntohs(ep_pkt.length);
+	ep_pkt.sliceLength = ntohs(ep_pkt.sliceLength);
+	ep_pkt.timestamp = ntohl(ep_pkt.timestamp);
+	ep_pkt.destNum = ntohs(ep_pkt.destNum);
+	ep_pkt.srcNum = ntohs(ep_pkt.srcNum);
+	ep_pkt.protoNum = ntohs(ep_pkt.protoNum);
+
+	/* force sliceLength to be the actual length of the packet */
+	if (0 == ep_pkt.sliceLength) {
+		ep_pkt.sliceLength = ep_pkt.length;
+	}
+
+	/* test for corrupt data */
+	if (ep_pkt.sliceLength > WTAP_MAX_PACKET_SIZE) {
+		*err = WTAP_ERR_BAD_RECORD;
+		return FALSE;
+	}
+
+	*data_offset = wth->data_offset;
+
+	/* fill in packet header values */
+	wth->phdr.len        = ep_pkt.length;
+	wth->phdr.caplen     = ep_pkt.sliceLength;
+	/* timestamp is in milliseconds since reference_time */
+	wth->phdr.ts.tv_sec  = wth->pseudo_header.etherpeek.
+		reference_time.tv_sec + (ep_pkt.timestamp / 1000);
+	wth->phdr.ts.tv_usec = 1000 * (ep_pkt.timestamp % 1000);
+	
+	wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
+	for (i=0; i<NUM_ETHERPEEK_ENCAPS; i++) {
+		if (etherpeek_encap[i].protoNum == ep_pkt.protoNum) {
+			wth->phdr.pkt_encap = etherpeek_encap[i].encap;
+		}
+	}
+
+	return TRUE;
+}
diff -Naur ethereal-0.8.15/wiretap/etherpeek.h ethereal/wiretap/etherpeek.h
--- ethereal-0.8.15/wiretap/etherpeek.h	Thu Jan  1 01:00:00 1970
+++ ethereal/wiretap/etherpeek.h	Sat Feb  3 09:37:25 2001
@@ -0,0 +1,29 @@
+/* etherpeek.h
+ *
+ * $Id: snoop.h,v 1.8 2000/08/11 13:32:34 deniel Exp $
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@xxxxxxxxxx>
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef __W_ETHERPEEK_H__
+#define __W_ETHERPEEK_H__
+
+int etherpeek_open(wtap *wth, int *err);
+
+#endif
diff -Naur ethereal-0.8.15/wiretap/file.c ethereal/wiretap/file.c
--- ethereal-0.8.15/wiretap/file.c	Tue Sep 19 18:22:09 2000
+++ ethereal/wiretap/file.c	Sat Feb  3 09:50:09 2001
@@ -59,6 +59,7 @@
 #include "i4btrace.h"
 #include "csids.h"
 #include "pppdump.h"
+#include "etherpeek.h"
 
 /* The open_file_* routines should return:
  *
@@ -96,6 +97,7 @@
 	radcom_open,
 	nettl_open,
 	pppdump_open,
+	etherpeek_open,
 
 	/* Files whose magic headers are in text *somewhere* in the
 	 * file (usually because the trace is just a saved copy of
@@ -345,6 +347,13 @@
         { "pppd log (pppdump format)", NULL,
           NULL, NULL },
 
+	/* WTAP_FILE_ETHERPEEK_MAC_V56 */
+	{ "Etherpeek trace (Macintosh V5 & V6)", NULL,
+	  NULL, NULL },
+
+	/* WTAP_FILE_ETHERPEEK_MAC_V7 */
+	{ "Etherpeek trace (Macintosh V7)", NULL,
+	  NULL, NULL },
 };
 
 /* Name that should be somewhat descriptive. */
diff -Naur ethereal-0.8.15/wiretap/wtap.h ethereal/wiretap/wtap.h
--- ethereal-0.8.15/wiretap/wtap.h	Mon Jan  8 22:18:22 2001
+++ ethereal/wiretap/wtap.h	Thu Feb 22 20:18:56 2001
@@ -129,9 +129,11 @@
 #define WTAP_FILE_I4BTRACE			22
 #define WTAP_FILE_CSIDS				23
 #define WTAP_FILE_PPPDUMP			24
+#define WTAP_FILE_ETHERPEEK_MAC_V56		25
+#define WTAP_FILE_ETHERPEEK_MAC_V7		26
 
 /* last WTAP_FILE_ value + 1 */
-#define WTAP_NUM_FILE_TYPES			25
+#define WTAP_NUM_FILE_TYPES			27
 
 /*
  * Maximum packet size we'll support.
@@ -189,6 +191,10 @@
 	guint32	task;			/* Task number */
 };
 
+/* Packet "pseudo_header" for etherpeek capture files. */
+struct etherpeek_phdr {
+	struct timeval reference_time;
+};
 
 struct p2p_phdr {
 	gboolean	sent; /* TRUE=sent, FALSE=received */
@@ -251,6 +257,7 @@
 	struct x25_phdr			x25;
 	struct ngsniffer_atm_phdr	ngsniffer_atm;
 	struct ascend_phdr		ascend;
+	struct etherpeek_phdr           etherpeek;
 	struct p2p_phdr			p2p;
 };