diff --git a/wiretap/AUTHORS b/wiretap/AUTHORS index f1ab766109..b9a58ff61f 100644 --- a/wiretap/AUTHORS +++ b/wiretap/AUTHORS @@ -18,3 +18,5 @@ Markus Steinmann Mark C. Brown Martin Warnes Thierry Martin +Jesper Peterson + diff --git a/wiretap/Makefile.am b/wiretap/Makefile.am index 88d0f64b50..e4501e52c6 100644 --- a/wiretap/Makefile.am +++ b/wiretap/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for Wiretap # -# $Id: Makefile.am,v 1.44 2003/08/23 08:34:11 guy Exp $ +# $Id: Makefile.am,v 1.45 2003/08/26 07:10:38 guy Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs @@ -47,6 +47,8 @@ libwiretap_a_SOURCES = \ csids.h \ dbs-etherwatch.c \ dbs-etherwatch.h \ + erf.c \ + erf.h \ etherpeek.c \ etherpeek.h \ file_access.c \ diff --git a/wiretap/Makefile.nmake b/wiretap/Makefile.nmake index 0adefbcb69..952841fe26 100644 --- a/wiretap/Makefile.nmake +++ b/wiretap/Makefile.nmake @@ -1,5 +1,5 @@ # -# $Id: Makefile.nmake,v 1.33 2003/08/23 08:34:11 guy Exp $ +# $Id: Makefile.nmake,v 1.34 2003/08/26 07:10:38 guy Exp $ # include ..\config.nmake @@ -21,6 +21,7 @@ OBJECTS=ascend-grammar.obj \ cosine.obj \ csids.obj \ dbs-etherwatch.obj \ + erf.obj \ etherpeek.obj \ file_access.obj \ file_wrappers.obj \ diff --git a/wiretap/erf.c b/wiretap/erf.c new file mode 100644 index 0000000000..6332b3022b --- /dev/null +++ b/wiretap/erf.c @@ -0,0 +1,412 @@ +/* +* +* Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand. +* All rights reserved. +* +* This software and documentation has been developed by Endace Technology Ltd. +* along with the DAG PCI network capture cards. For further information please +* visit http://www.endace.com/. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. The name of Endace Technology Ltd may not be used to endorse or promote +* products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS +* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* $Id: erf.c,v 1.1 2003/08/26 07:10:38 guy Exp $ +*/ + +/* + * erf - Endace ERF (Extensible Record Format) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "wtap-int.h" +#include "file_wrappers.h" +#include "buffer.h" +#include "atm.h" +#include "erf.h" + +typedef guint32 atm_hdr_t; + +static int erf_read_header( + FILE_T fh, + struct wtap_pkthdr *phdr, + union wtap_pseudo_header *pseudo_header, + erf_header_t *erf_header, + erf_t *erf, + int *err, + guint32 *bytes_read, + guint32 *packet_size); +static gboolean erf_read(wtap *wth, int *err, long *data_offset); +static gboolean erf_seek_read(wtap *wth, long seek_off, + union wtap_pseudo_header *pseudo_header, guchar *pd, + int length, int *err); +static void erf_close(wtap *wth); +static int erf_encap_to_wtap_encap(erf_t *erf, guint8 erf_encap); + +int erf_open(wtap *wth, int *err) +{ + guint32 i, n; + char *s; + guint32 records_for_erf_check = RECORDS_FOR_ERF_CHECK; + guint32 atm_encap = WTAP_ENCAP_ATM_RFC1483; + gboolean is_rawatm = FALSE; + gboolean is_ppp = FALSE; + int common_type = 0; + erf_timestamp_t prevts; + + memset(&prevts, 0, sizeof(prevts)); + + if ((s = getenv("ERF_ATM_ENCAP")) != NULL) { + if (!strcmp(s, "sunatm")) { + atm_encap = WTAP_ENCAP_ATM_PDUS; + } else + if (!strcmp(s, "sunraw")) { + atm_encap = WTAP_ENCAP_ATM_PDUS; + is_rawatm = TRUE; + } + } + + /* number of records to scan before deciding if this really is ERF (dflt=3) */ + if ((s = getenv("ERF_RECORDS_TO_CHECK")) != NULL) { + if ((n = atoi(s)) > 0 && n < 101) { + records_for_erf_check = n; + } + } + + /* ERF is a little hard because there's no magic number */ + + for (i = 0; i < records_for_erf_check; i++) { + + erf_header_t header; + guint32 packet_size; + erf_timestamp_t ts; + + if (file_read(&header,1,sizeof(header),wth->fh) != sizeof(header)) { + if ((*err = file_error(wth->fh)) != 0) + return -1; + else + break; /* eof */ + } + + packet_size = g_ntohs(header.rlen) - sizeof(header); + + /* fail on invalid record type, decreasing timestamps or non-zero pad-bits */ + if (header.type == 0 || header.type > TYPE_AAL5 || + (header.flags & 0xc0) != 0) { + return 0; + } + +#ifdef G_HAVE_GINT64 + if ((ts = pletohll(&header.ts)) < prevts) { + return 0; + } +#else + ts[0] = pletohl(&header.ts[0]); /* frac */ + ts[1] = pletohl(&header.ts[1]); /* sec */ + if ((ts[1] < prevts[1]) || + (ts[1] == prevts[1] && ts[0] < prevts[0])) { + return 0; + } +#endif + memcpy(&prevts, &ts, sizeof(prevts)); + + if (common_type == 0) { + common_type = header.type; + } else + if (common_type > 0 && common_type != header.type) { + common_type = -1; + } + + if (header.type == TYPE_HDLC_POS && !is_ppp) { + guint16 chdlc_hdr; + if (file_read(&chdlc_hdr,1,sizeof(chdlc_hdr),wth->fh) != sizeof(chdlc_hdr)) { + *err = file_error(wth->fh); + } + packet_size -= sizeof(chdlc_hdr); + if (g_ntohs(chdlc_hdr) == 0xff03) { + is_ppp = TRUE; + } + } + + if (file_seek(wth->fh, packet_size, SEEK_CUR, err) == -1) { + return -1; + } + } + + if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) { /* rewind */ + return -1; + } + + wth->data_offset = 0; + + /* This is an ERF file */ + wth->file_type = WTAP_FILE_ERF; + wth->snapshot_length = 0; /* not available in header, only in frame */ + wth->capture.erf = g_malloc(sizeof(erf_t)); + wth->capture.erf->atm_encap = atm_encap; + wth->capture.erf->is_rawatm = is_rawatm; + wth->capture.erf->is_ppp = is_ppp; + + /* + * Really want WTAP_ENCAP_PER_PACKET here but that severely limits + * the number of output formats we can write to. If all the records + * tested in the loop above were the same encap then use that one, + * otherwise use WTAP_ENCAP_PER_PACKET. + */ + wth->file_encap = + (common_type < 0 + ? WTAP_ENCAP_PER_PACKET + : erf_encap_to_wtap_encap(wth->capture.erf, common_type)); + + wth->subtype_read = erf_read; + wth->subtype_seek_read = erf_seek_read; + wth->subtype_close = erf_close; + + return 1; +} + +/* Read the next packet */ +static gboolean erf_read(wtap *wth, int *err, long *data_offset) +{ + erf_header_t erf_header; + guint32 packet_size, bytes_read; + gint32 offset = 0; + + *data_offset = wth->data_offset; + + if (!erf_read_header( + wth->fh, + &wth->phdr, &wth->pseudo_header, &erf_header, wth->capture.erf, + err, &bytes_read, &packet_size)) { + return FALSE; + } + wth->data_offset += bytes_read; + + buffer_assure_space(wth->frame_buffer, packet_size+(wth->capture.erf->is_rawatm?(sizeof(atm_hdr_t)+1):0)); + + if (wth->capture.erf->is_rawatm) { + wtap_file_read_expected_bytes( + buffer_start_ptr(wth->frame_buffer), (gint32)sizeof(atm_hdr_t), wth->fh, err + ); + wth->data_offset += sizeof(atm_hdr_t); + packet_size -= sizeof(atm_hdr_t); + offset += sizeof(atm_hdr_t)+1; + } + + wtap_file_read_expected_bytes( + buffer_start_ptr(wth->frame_buffer)+offset, (gint32)packet_size, wth->fh, err + ); + wth->data_offset += packet_size; + + if (erf_header.type == TYPE_ATM && wth->capture.erf->atm_encap == WTAP_ENCAP_ATM_PDUS && !wth->capture.erf->is_rawatm) { + atm_guess_traffic_type( + buffer_start_ptr(wth->frame_buffer), packet_size, &wth->pseudo_header + ); + } + + return TRUE; +} + +static gboolean erf_seek_read(wtap *wth, long seek_off, + union wtap_pseudo_header *pseudo_header, guchar *pd, + int length, int *err) +{ + erf_header_t erf_header; + guint32 packet_size; + + if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) + return FALSE; + + erf_read_header(wth->random_fh, NULL, pseudo_header, &erf_header, wth->capture.erf, err, NULL, &packet_size); + + if (wth->capture.erf->is_rawatm) { + wtap_file_read_expected_bytes(pd, (int)sizeof(atm_hdr_t), wth->random_fh, err); + pd += sizeof(atm_hdr_t)+1; + } + + wtap_file_read_expected_bytes(pd, (int)packet_size, wth->random_fh, err); + + if (erf_header.type == TYPE_ATM && wth->capture.erf->atm_encap == WTAP_ENCAP_ATM_PDUS && !wth->capture.erf->is_rawatm) { + atm_guess_traffic_type(pd, length, pseudo_header); + } + + return TRUE; +} + +static void erf_close(wtap *wth) +{ + g_free(wth->capture.erf); +} + +static int erf_read_header( + FILE_T fh, + struct wtap_pkthdr *phdr, + union wtap_pseudo_header *pseudo_header, + erf_header_t *erf_header, + erf_t *erf, + int *err, + guint32 *bytes_read, + guint32 *packet_size) +{ + guint32 rec_size, skip; + + wtap_file_read_expected_bytes(erf_header, sizeof(*erf_header), fh, err); + if (bytes_read != NULL) { + *bytes_read = sizeof(*erf_header); + } + + rec_size = g_ntohs(erf_header->rlen); + *packet_size = rec_size - sizeof(*erf_header); + skip = 0; /* # bytes of payload to ignore */ + + if (*packet_size > WTAP_MAX_PACKET_SIZE) { + /* + * Probably a corrupt capture file; don't blow up trying + * to allocate space for an immensely-large packet. + */ + g_message("erf: File has %u-byte packet, bigger than maximum of %u", + *packet_size, WTAP_MAX_PACKET_SIZE); + *err = WTAP_ERR_BAD_RECORD; + return FALSE; + } + + if (phdr != NULL ) { +#ifdef G_HAVE_GINT64 + guint64 ts = pletohll(&erf_header->ts); + + phdr->ts.tv_sec = ts >> 32; + ts = ((ts & 0xffffffffULL) * 1000 * 1000); + ts += (ts & 0x80000000ULL) << 1; /* rounding */ + phdr->ts.tv_usec = ts >> 32; + if (phdr->ts.tv_usec >= 1000000) { + phdr->ts.tv_usec -= 1000000; + phdr->ts.tv_sec += 1; + } +#else + phdr->ts.tv_sec = pletohl(&erf_header->ts[1]); + phdr->ts.tv_usec = + (unsigned long)((pletohl(&erf_header->ts[0])*1000000.0)/0xffffffffUL); +#endif + } + + switch (erf_header->type) { + + case TYPE_ATM: + + if (phdr != NULL) { + phdr->caplen = ATM_SLEN(erf_header, NULL); + phdr->len = ATM_WLEN(erf_header, NULL); + } + + if (erf->atm_encap == WTAP_ENCAP_ATM_PDUS) { + memset(&pseudo_header->atm, 0, sizeof(pseudo_header->atm)); + if (erf->is_rawatm) { + pseudo_header->atm.flags = ATM_RAW_CELL; + if (phdr != NULL) { + phdr->caplen += sizeof(atm_hdr_t)+1; + phdr->len += sizeof(atm_hdr_t)+1; + } + } else { + atm_hdr_t atm_hdr; + + wtap_file_read_expected_bytes(&atm_hdr, sizeof(atm_hdr), fh, err); + if (bytes_read != NULL) { + *bytes_read += sizeof(atm_hdr); + } + *packet_size -= sizeof(atm_hdr); + + atm_hdr = g_ntohl(atm_hdr); + + pseudo_header->atm.vpi = ((atm_hdr & 0x0ff00000) >> 20); + pseudo_header->atm.vci = ((atm_hdr & 0x000ffff0) >> 4); + pseudo_header->atm.channel = (erf_header->flags & 0x03); + } + } else { + skip = 4; + } + break; + case TYPE_ETH: + if (phdr != NULL) { + phdr->caplen = ETHERNET_SLEN(erf_header, erf); + phdr->len = ETHERNET_WLEN(erf_header, erf); + } + skip = 2; + break; + case TYPE_HDLC_POS: + if (phdr != NULL) { + phdr->caplen = HDLC_SLEN(erf_header, erf); + phdr->len = HDLC_WLEN(erf_header, erf); + } + memset(&pseudo_header->p2p, 0, sizeof(pseudo_header->p2p)); + pseudo_header->p2p.sent = ((erf_header->flags & 0x01) ? TRUE : FALSE); + break; + default: + *err = WTAP_ERR_UNSUPPORTED_ENCAP; + return FALSE; + } + + if (phdr != NULL) { + phdr->pkt_encap = erf_encap_to_wtap_encap(erf, erf_header->type); + } + + if (skip > 0) { + if (file_seek(fh, skip, SEEK_CUR, err) == -1) { + return FALSE; + } + if (bytes_read != NULL) { + *bytes_read += skip; + } + *packet_size -= skip; + } + + return TRUE; +} + +static int erf_encap_to_wtap_encap(erf_t *erf, guint8 erf_encap) +{ + int wtap_encap = WTAP_ENCAP_UNKNOWN; + + switch (erf_encap) { + case TYPE_ATM: + case TYPE_AAL5: + wtap_encap = erf->atm_encap; + break; + case TYPE_ETH: + wtap_encap = WTAP_ENCAP_ETHERNET; + break; + case TYPE_HDLC_POS: + wtap_encap = (erf->is_ppp ? WTAP_ENCAP_PPP : WTAP_ENCAP_CHDLC); + break; + default: + break; + } + + return wtap_encap; +} diff --git a/wiretap/erf.h b/wiretap/erf.h new file mode 100644 index 0000000000..ff9daa2dbd --- /dev/null +++ b/wiretap/erf.h @@ -0,0 +1,101 @@ +/* +* +* Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand. +* All rights reserved. +* +* This software and documentation has been developed by Endace Technology Ltd. +* along with the DAG PCI network capture cards. For further information please +* visit http://www.endace.com/. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. The name of Endace Technology Ltd may not be used to endorse or promote +* products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS +* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* $Id: erf.h,v 1.1 2003/08/26 07:10:38 guy Exp $ +*/ + +#ifndef __W_ERF_H__ +#define __W_ERF_H__ + +/* Record type defines */ +#define TYPE_LEGACY 0 +#define TYPE_HDLC_POS 1 +#define TYPE_ETH 2 +#define TYPE_ATM 3 +#define TYPE_AAL5 4 + + /* + * The timestamp is 64bit unsigned fixed point little-endian value with + * 32 bits for second and 32 bits for fraction. For portablility it is + * given as two 32 bit valies here, ts[1] == secs, ts[0] == fraction + */ +#ifdef G_HAVE_GINT64 +typedef guint64 erf_timestamp_t; +#else +typedef guint32 erf_timestamp_t[2]; +#endif + +typedef struct erf_record { + erf_timestamp_t ts; + guint8 type; + guint8 flags; + guint16 rlen; + guint16 lctr; + guint16 wlen; +} erf_header_t; + +#define MAX_RECORD_LEN 0x10000 /* 64k */ +#define RECORDS_FOR_ERF_CHECK 3 +#define FCS_BITS 32 + +#ifndef min +#define min(a, b) ((a) > (b) ? (b) : (a)) +#endif + +/* + * ATM snaplength + */ +#define ATM_SNAPLEN 48 + +/* + * Size of ATM payload + */ +#define ATM_SLEN(h, e) ATM_SNAPLEN +#define ATM_WLEN(h, e) ATM_SNAPLEN + +/* + * Size of Ethernet payload + */ +#define ETHERNET_WLEN(h, e) (g_htons((h)->wlen)) +#define ETHERNET_SLEN(h, e) min(ETHERNET_WLEN(h, e), g_htons((h)->rlen) - sizeof(*(h)) - 2) + +/* + * Size of HDLC payload + */ +#define HDLC_WLEN(h, e) (g_htons((h)->wlen)) +#define HDLC_SLEN(h, e) min(HDLC_WLEN(h, e), g_htons((h)->rlen) - sizeof(*(h))) + +int erf_open(wtap *wth, int *err); + +#endif /* __W_ERF_H__ */ diff --git a/wiretap/file_access.c b/wiretap/file_access.c index 1ace8a055a..25d7a92584 100644 --- a/wiretap/file_access.c +++ b/wiretap/file_access.c @@ -1,6 +1,6 @@ /* file_access.c * - * $Id: file_access.c,v 1.1 2003/08/23 08:34:12 guy Exp $ + * $Id: file_access.c,v 1.2 2003/08/26 07:10:38 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -69,6 +69,7 @@ #include "visual.h" #include "cosine.h" #include "5views.h" +#include "erf.h" /* The open_file_* routines should return: * @@ -118,6 +119,7 @@ static int (*const open_routines[])(wtap *, int *) = { vms_open, dbs_etherwatch_open, cosine_open, + erf_open, }; #define N_FILE_TYPES (sizeof open_routines / sizeof open_routines[0]) @@ -448,6 +450,10 @@ static const struct file_type_info { /* WTAP_FILE_5VIEWS */ { "Accellent 5Views capture", "5views", _5views_dump_can_write_encap, _5views_dump_open }, + + /* WTAP_FILE_ERF */ + { "Endace DAG capture", "erf", + NULL, NULL }, }; /* Name that should be somewhat descriptive. */ diff --git a/wiretap/wtap-int.h b/wiretap/wtap-int.h index a02d313876..47c4389cab 100644 --- a/wiretap/wtap-int.h +++ b/wiretap/wtap-int.h @@ -1,6 +1,6 @@ /* wtap-int.h * - * $Id: wtap-int.h,v 1.38 2003/07/29 20:49:32 guy Exp $ + * $Id: wtap-int.h,v 1.39 2003/08/26 07:10:39 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -117,6 +117,12 @@ typedef struct { struct timeval reference_time; } etherpeek_t; +typedef struct { + guint32 atm_encap; + gboolean is_rawatm; + gboolean is_ppp; +} erf_t; + typedef gboolean (*subtype_read_func)(struct wtap*, int*, long*); typedef gboolean (*subtype_seek_read_func)(struct wtap*, long, union wtap_pseudo_header*, guint8*, int, int *); @@ -143,6 +149,7 @@ struct wtap { ascend_t *ascend; csids_t *csids; etherpeek_t *etherpeek; + erf_t *erf; void *generic; } capture; diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 69d2c9ba75..98d8f8a02f 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -1,6 +1,6 @@ /* wtap.h * - * $Id: wtap.h,v 1.139 2003/07/29 19:42:01 guy Exp $ + * $Id: wtap.h,v 1.140 2003/08/26 07:10:39 guy Exp $ * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez @@ -170,9 +170,10 @@ #define WTAP_FILE_VISUAL_NETWORKS 32 #define WTAP_FILE_COSINE 33 #define WTAP_FILE_5VIEWS 34 +#define WTAP_FILE_ERF 35 /* last WTAP_FILE_ value + 1 */ -#define WTAP_NUM_FILE_TYPES 35 +#define WTAP_NUM_FILE_TYPES 36 /* * Maximum packet size we'll support.