diff options
-rw-r--r-- | wiretap/Makefile.common | 2 | ||||
-rw-r--r-- | wiretap/file_access.c | 8 | ||||
-rw-r--r-- | wiretap/libwiretap.vcproj | 8 | ||||
-rw-r--r-- | wiretap/pcapng.c | 985 | ||||
-rw-r--r-- | wiretap/pcapng.h | 30 | ||||
-rw-r--r-- | wiretap/wtap-int.h | 7 | ||||
-rw-r--r-- | wiretap/wtap.h | 1 |
7 files changed, 1040 insertions, 1 deletions
diff --git a/wiretap/Makefile.common b/wiretap/Makefile.common index 80a3515b5f..57d276acae 100644 --- a/wiretap/Makefile.common +++ b/wiretap/Makefile.common @@ -60,6 +60,7 @@ NONGENERATED_C_FILES = \ network_instruments.c \ netxray.c \ ngsniffer.c \ + pcapng.c \ pppdump.c \ radcom.c \ snoop.c \ @@ -103,6 +104,7 @@ NONGENERATED_HEADER_FILES = \ network_instruments.h \ netxray.h \ ngsniffer.h \ + pcapng.h \ pppdump.h \ radcom.h \ snoop.h \ diff --git a/wiretap/file_access.c b/wiretap/file_access.c index 8a743fb9a1..9ba0c7584b 100644 --- a/wiretap/file_access.c +++ b/wiretap/file_access.c @@ -75,6 +75,7 @@ #include "mpeg.h" #include "netscreen.h" #include "commview.h" +#include "pcapng.h" @@ -118,6 +119,7 @@ static wtap_open_routine_t open_routines_base[] = { catapult_dct2000_open, ber_open, mpeg_open, + pcapng_open, /* Files that don't have magic bytes at a fixed location, * but that instead require a heuristic of some sort to * identify them. This includes the ASCII trace files that @@ -572,7 +574,11 @@ static const struct file_type_info dump_open_table_base[] = { /* WTAP_FILE_COMMVIEW */ { "TamoSoft CommView", "commview", "*.ncf", ".ncf", TRUE, - commview_dump_can_write_encap, commview_dump_open } + commview_dump_can_write_encap, commview_dump_open }, + + /* WTAP_FILE_PCAPNG */ + { "Wireshark - pcapng (experimental)", "pcapng", "*.pcapng", NULL, FALSE, + pcapng_dump_can_write_encap, pcapng_dump_open } }; gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info); diff --git a/wiretap/libwiretap.vcproj b/wiretap/libwiretap.vcproj index 3e45910cfe..82ada99379 100644 --- a/wiretap/libwiretap.vcproj +++ b/wiretap/libwiretap.vcproj @@ -188,6 +188,10 @@ >
</File>
<File
+ RelativePath=".\pcapng.c"
+ >
+ </File>
+ <File
RelativePath=".\pppdump.c"
>
</File>
@@ -350,6 +354,10 @@ >
</File>
<File
+ RelativePath=".\pcapng.h"
+ >
+ </File>
+ <File
RelativePath=".\pppdump.h"
>
</File>
diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c new file mode 100644 index 0000000000..20eff30d32 --- /dev/null +++ b/wiretap/pcapng.c @@ -0,0 +1,985 @@ +/* pcapng.c
+ *
+ * $Id: pcapng.c 22849 2007-09-11 21:31:21Z jake $
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * File format support for pcap-ng file format
+ * Copyright (c) 2007 by Ulf Lamping <ulf.lamping@web.de>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "wtap-int.h"
+#include "file_wrappers.h"
+#include "buffer.h"
+
+
+static gboolean
+pcapng_read(wtap *wth, int *err, gchar **err_info,
+ gint64 *data_offset);
+static gboolean
+pcapng_seek_read(wtap *wth, gint64 seek_off,
+ union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
+ int *err, gchar **err_info);
+static void
+pcapng_close(wtap *wth);
+
+
+
+/* pcapng: common block header for every block type */
+typedef struct pcapng_block_header_s {
+ guint32 block_type;
+ guint32 block_total_length;
+ /* x bytes block_body */
+ /* guint32 block_total_length */
+} pcapng_block_header_t;
+
+/* pcapng: section header block */
+typedef struct pcapng_section_header_block_s {
+ /* pcapng_block_header_t */
+ guint32 magic;
+ guint16 version_major;
+ guint16 version_minor;
+ guint64 section_length; /* might be -1 for unknown */
+ /* ... Options ... */
+} pcapng_section_header_block_t;
+
+/* pcapng: interface description block */
+typedef struct pcapng_interface_description_block_s {
+ guint16 linktype;
+ guint16 reserved;
+ guint32 snaplen;
+ /* ... Options ... */
+} pcapng_interface_description_block_t;
+
+/* pcapng: packet block (obsolete) */
+typedef struct pcapng_packet_block_s {
+ guint16 interface_id;
+ guint16 reserved;
+ guint32 timestamp_high;
+ guint32 timestamp_low;
+ guint32 captured_len;
+ guint32 packet_len;
+ /* ... Packet Data ... */
+ /* ... Padding ... */
+ /* ... Options ... */
+} pcapng_packet_block_t;
+
+/* pcapng: enhanced packet block */
+typedef struct pcapng_enhanced_packet_block_s {
+ guint32 interface_id;
+ guint32 timestamp_high;
+ guint32 timestamp_low;
+ guint32 captured_len;
+ guint32 packet_len;
+ /* ... Packet Data ... */
+ /* ... Padding ... */
+ /* ... Options ... */
+} pcapng_enhanced_packet_block_t;
+
+
+
+
+
+
+/* Capture section */
+typedef struct wtapng_section_s {
+ /* mandatory */
+ guint64 section_length;
+ /* options */
+ gchar *opt_comment; /* NULL if not available */
+ gchar *shb_hardware; /* NULL if not available */
+ gchar *shb_os; /* NULL if not available */
+ gchar *shb_user_appl; /* NULL if not available */
+} wtapng_section_t;
+
+/* Interface Description */
+typedef struct wtapng_if_descr_s {
+ /* mandatory */
+ guint16 link_type;
+ guint32 snap_len;
+ /* options */
+ gchar *opt_comment; /* NULL if not available */
+ gchar *if_name; /* NULL if not available */
+ gchar *if_description;/* NULL if not available */
+ /* XXX: if_IPv4addr */
+ /* XXX: if_IPv6addr */
+ /* XXX: if_MACaddr */
+ /* XXX: if_EUIaddr */
+ guint64 if_speed; /* 0xFFFFFFFF if unknown */
+ guint8 if_tsaccur; /* default is 6 for microsecond resolution */
+ /* XXX: if_filter */
+ gchar *if_os; /* NULL if not available */
+ gchar if_fcslen; /* -1 if unknown or changes between packets */
+ /* XXX: guint64 if_tsoffset; */
+} wtapng_if_descr_t;
+
+/* Packets */
+typedef struct wtapng_packet_s {
+ /* mandatory */
+ guint32 ts_high; /* seconds since 1.1.1970 */
+ guint32 ts_low; /* fraction of seconds, depends on if_tsaccur */
+ guint32 cap_len;
+ guint32 packet_len;
+ /* options */
+ gchar *opt_comment; /* NULL if not available */
+ guint64 drop_count; /* 0xFFFFFFFF if unknown */
+ /* pack_flags */
+ /* pack_hash */
+
+ /* XXX - put the packet data / pseudo_header here as well? */
+} wtapng_packet_t;
+
+/* Name Resolution */
+typedef struct wtapng_name_res_s {
+ /* options */
+ gchar *opt_comment; /* NULL if not available */
+ /* XXX */
+} wtapng_name_res_t;
+
+/* Interface Statistics */
+typedef struct wtapng_if_stats_s {
+ /* mandatory */
+ guint32 ts_high;
+ guint32 ts_low;
+ /* options */
+ gchar *opt_comment; /* NULL if not available */
+ /* XXX */
+ /*guint32 isb_starttime_high;*/
+ /*guint32 isb_starttime_low;*/
+ /*guint32 isb_endtime_high;*/
+ /*guint32 isb_endtime_low;*/
+ /*guint64 isb_ifrecv;*/
+ /*guint64 isb_ifdrop;*/
+ /*guint64 isb_filteraccept;*/
+ /*guint64 isb_osdrop;*/
+ /*guint64 isb_usrdeliv;*/
+} wtapng_if_stats_t;
+
+
+typedef struct wtapng_block_s {
+ guint32 type; /* block_type as defined by pcapng */
+ union {
+ wtapng_section_t section;
+ wtapng_if_descr_t if_descr;
+ wtapng_packet_t packet;
+ wtapng_name_res_t name_res;
+ wtapng_if_stats_t if_stats;
+ } data;
+
+ /* XXX - currently don't know how to handle these! */
+ const union wtap_pseudo_header *pseudo_header;
+ const guchar *frame_buffer;
+} wtapng_block_t;
+
+
+static int
+pcapng_read_section_header_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
+{
+ int bytes_read;
+ int to_read;
+ pcapng_section_header_block_t shb;
+ guint64 file_offset64;
+
+
+ /* read block content */
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read = file_read(&shb, 1, sizeof shb, fh);
+ if (bytes_read != sizeof shb) {
+ *err = file_error(fh);
+ if (*err != 0)
+ return -1;
+ return 0;
+ }
+
+ /* is the magic number one we expect? */
+ switch(shb.magic) {
+ case(0x1A2B3C4D):
+ /* this seems pcapng with correct byte order */
+ pn->byte_swapped = FALSE;
+ pn->version_major = shb.version_major;
+ pn->version_minor = shb.version_minor;
+
+ g_warning("pcapng_read_section_header_block: SHB (little endian) V%u.%u, len %u",
+ pn->version_major, pn->version_minor, bh->block_total_length);
+ break;
+ case(0x4D3C2B1A):
+ /* this seems pcapng with swapped byte order */
+ pn->byte_swapped = TRUE;
+ pn->version_major = BSWAP16(shb.version_major);
+ pn->version_minor = BSWAP16(shb.version_minor);
+
+ /* tweak the block length to meet current swapping that we know now */
+ bh->block_total_length = BSWAP32(bh->block_total_length);
+
+ g_warning("pcapng_read_section_header_block: SHB (big endian) V%u.%u, len %u",
+ pn->version_major, pn->version_minor, bh->block_total_length);
+ break;
+ default:
+ /* Not a "pcapng" magic number we know about. */
+ g_warning("pcapng_read_section_header_block: unknown magic number %u (probably not an pcapng file)", shb.magic);
+ return 0;
+ }
+
+ /* we currently only understand SHB V1.0 */
+ if(pn->version_major != 1 || pn->version_minor != 0) {
+ g_warning("pcapng_read_section_header_block: unknown SHB version %u.%u",
+ pn->version_major, pn->version_minor);
+ return 0;
+ }
+
+ /* XXX - no proper way to read/swap 64 bit values -> so ignore the 64bit section_length for now! */
+ wblock->data.section.section_length = -1; /* shb.section_length */
+
+ /* XXX - we ignore SHB options for now */
+ /* "Section Header Block" jump over the Options (and the repeated block length at the end) */
+ errno = WTAP_ERR_CANT_READ;
+ to_read = bh->block_total_length - sizeof(pcapng_block_header_t) - sizeof (pcapng_section_header_block_t);
+ file_offset64 = file_seek(fh, to_read, SEEK_CUR, err);
+ if (file_offset64 <= 0) {
+ if (*err != 0)
+ return -1;
+ return 0;
+ }
+
+ /* options */
+ wblock->data.section.opt_comment = NULL;
+ wblock->data.section.shb_hardware = NULL;
+ wblock->data.section.shb_os = NULL;
+ wblock->data.section.shb_user_appl = NULL;
+
+ return bytes_read + to_read;
+}
+
+
+/* "Interface Description Block" */
+static int
+pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
+{
+ int bytes_read;
+ int to_read;
+ guint64 file_offset64;
+ pcapng_interface_description_block_t idb;
+
+
+ /* read block content */
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read = file_read(&idb, 1, sizeof idb, fh);
+ if (bytes_read != sizeof idb) {
+ g_warning("pcapng_read_if_descr_block: failed to read IDB");
+ *err = file_error(fh);
+ if (*err != 0)
+ return -1;
+ return 0;
+ }
+
+ /* mandatory */
+ if(pn->byte_swapped) {
+ wblock->data.if_descr.link_type = BSWAP16(idb.linktype);
+ wblock->data.if_descr.snap_len = BSWAP32(idb.snaplen);
+ } else {
+ wblock->data.if_descr.link_type = idb.linktype;
+ wblock->data.if_descr.snap_len = idb.snaplen;
+ }
+
+ g_warning("pcapng_read_if_descr_block: IDB link_type %u, snap %u",
+ wblock->data.if_descr.link_type, wblock->data.if_descr.snap_len);
+
+ /* XXX - sanity check of snapshot length */
+ /* XXX - while a very big snapshot length is valid, it's more likely that it's a bug in the file */
+ /* XXX - so do a sanity check for now, it's likely a byte swap order problem */
+ if(wblock->data.if_descr.snap_len > 65535) {
+ g_warning("pcapng_read_if_descr_block: snapshot length %u unrealistic",
+ pcapng_read_if_descr_block);
+ /*wblock->data.if_descr.snap_len = 65535;*/
+ return 0;
+ }
+
+ /* XXX - we ignore IDB options for now */
+ /* jump over the Options (and the repeated block length at the end) */
+ errno = WTAP_ERR_CANT_READ;
+ to_read = bh->block_total_length - sizeof(pcapng_block_header_t) - sizeof (pcapng_interface_description_block_t);
+ file_offset64 = file_seek(fh, to_read, SEEK_CUR, err);
+ if (file_offset64 <= 0) {
+ if (*err != 0)
+ return -1;
+ return 0;
+ }
+
+ /* options */
+ wblock->data.if_descr.opt_comment = NULL;
+ wblock->data.if_descr.if_name = NULL;
+ wblock->data.if_descr.if_description = NULL;
+ /* XXX: if_IPv4addr */
+ /* XXX: if_IPv6addr */
+ /* XXX: if_MACaddr */
+ /* XXX: if_EUIaddr */
+ wblock->data.if_descr.if_speed = 0xFFFFFFFF; /* "unknown" */
+ wblock->data.if_descr.if_tsaccur = 6; /* default is 6 for microsecond resolution */
+ /* XXX: if_filter */
+ wblock->data.if_descr.if_os = NULL;
+ wblock->data.if_descr.if_fcslen = (gchar) -1; /* unknown or changes between packets */
+ /* XXX: guint64 if_tsoffset; */
+
+ return bytes_read + to_read;
+}
+
+
+static int
+pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wtapng_block_t *wblock,int *err, gchar **err_info)
+{
+ int bytes_read;
+ guint64 bytes_read64;
+ int to_read;
+ pcapng_enhanced_packet_block_t epb;
+ int read_len = 0;
+ guint32 block_total_length;
+
+
+ /* "(Enhanced) Packet Block" read content */
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read = file_read(&epb, 1, sizeof epb, fh);
+ if (bytes_read != sizeof epb) {
+ g_warning("pcapng_read_packet_block: failed to read packet data");
+ *err = file_error(fh);
+ return 0;
+ }
+
+ read_len += sizeof epb;
+
+ /* XXX - as we currently ignore the interface id, both packet blocks are the same for us */
+ if(pn->byte_swapped) {
+ wblock->data.packet.ts_high = BSWAP32(epb.timestamp_high);
+ wblock->data.packet.ts_low = BSWAP32(epb.timestamp_low);
+ wblock->data.packet.cap_len = BSWAP32(epb.captured_len);
+ wblock->data.packet.packet_len = BSWAP32(epb.packet_len);
+ } else {
+ wblock->data.packet.ts_high = epb.timestamp_high;
+ wblock->data.packet.ts_low = epb.timestamp_low;
+ wblock->data.packet.cap_len = epb.captured_len;
+ wblock->data.packet.packet_len = epb.packet_len;
+ }
+
+ /*g_warning("pcapng_read_packet_block: packet data: packet_len %u captured_len %u",
+ wblock->data.packet.packet_len, wblock->data.packet.cap_len);*/
+
+ /* XXX - convert timestamps into nsecs */
+
+ /* XXX - implement other linktypes then Ethernet */
+ /* (or even better share the code with libpcap.c) */
+
+ /*
+ * We don't know whether there's an FCS in this frame or not.
+ */
+ ((union wtap_pseudo_header *) wblock->pseudo_header)->eth.fcs_len = -1;
+
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read = file_read((guchar *) (wblock->frame_buffer), 1, wblock->data.packet.cap_len, fh);
+ if (bytes_read != (int) wblock->data.packet.cap_len) {
+ *err = file_error(fh);
+ g_warning("pcapng_read_packet_block: couldn't read %u bytes of captured data",
+ wblock->data.packet.cap_len);
+ if (*err == 0)
+ *err = WTAP_ERR_SHORT_READ;
+ return FALSE;
+ }
+ read_len += wblock->data.packet.cap_len;
+
+ /* XXX - ignore Packet options for now */
+ /* Packet jump over the Options (and the repeated block length at the end) */
+
+ /* XXX - the "block total length" of some example files don't contain the padding bytes! */
+ if(bh->block_total_length % 4) {
+ block_total_length = bh->block_total_length + 4 - (bh->block_total_length % 4);
+ } else {
+ block_total_length = bh->block_total_length;
+ }
+
+ to_read = block_total_length - sizeof(pcapng_block_header_t) - sizeof (pcapng_enhanced_packet_block_t) - wblock->data.packet.cap_len;
+
+ /* jump over the data padding and the Options, but not the repeated block length */
+ to_read -= 4;
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read64 = file_seek(fh, to_read, SEEK_CUR, err);
+ if (bytes_read64 <= 0) {
+ return 0; /* Seek error */
+ }
+
+ /* sanity check: first and second block lengths must match */
+ /* XXX - move this out of the individual blocks into some common place? */
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read = file_read(&block_total_length, 1, sizeof block_total_length, fh);
+ if (bytes_read != sizeof block_total_length) {
+ *err = file_error(fh);
+ return 0;
+ }
+ if( !(block_total_length == bh->block_total_length) &&
+ !((BSWAP32(block_total_length)) == bh->block_total_length) ) {
+ g_warning("pcapng_read_packet_block: total block lengths (first %u and second %u) don't match",
+ bh->block_total_length, block_total_length);
+ return 0;
+ }
+
+ /* We read the packet successfully. */
+ return read_len + to_read;
+}
+
+
+
+
+static int
+pcapng_read_block(FILE_T fh, pcapng_t *pn, wtapng_block_t *wblock, int *err, gchar **err_info)
+{
+ int bytes_read_header;
+ int bytes_read_content;
+ pcapng_block_header_t bh;
+
+
+ /* Try to read the (next) block header */
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read_header = file_read(&bh, 1, sizeof bh, fh);
+ if (bytes_read_header != sizeof bh) {
+ g_warning("pcapng_read_block: no more bytes", sizeof bh);
+ *err = file_error(fh);
+ if (*err != 0)
+ return -1;
+ return 0;
+ }
+
+ if(pn->byte_swapped) {
+ bh.block_type = BSWAP32(bh.block_type);
+ bh.block_total_length = BSWAP32(bh.block_total_length);
+ }
+
+ wblock->type = bh.block_type;
+
+ /*g_warning("pcapng_read_block: block_type 0x%x", bh.block_type);*/
+
+ switch(bh.block_type) {
+ case(0x0A0D0D0A):
+ bytes_read_content = pcapng_read_section_header_block(fh, &bh, pn, wblock, err, err_info);
+ break;
+ case(1):
+ bytes_read_content = pcapng_read_if_descr_block(fh, &bh, pn, wblock, err, err_info);
+ break;
+ case(2):
+ bytes_read_content = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info);
+ break;
+ case(6):
+ bytes_read_content = pcapng_read_packet_block(fh, &bh, pn, wblock, err, err_info);
+ break;
+ default:
+ g_warning("pcapng_read_block: Unknown block_type: 0x%x", bh.block_type);
+ }
+
+ return (bytes_read_content == 0) ? 0 : bytes_read_header + bytes_read_content;
+}
+
+
+/* classic wtap: open capture file */
+int
+pcapng_open(wtap *wth, int *err, gchar **err_info)
+{
+ int bytes_read;
+ pcapng_t pn;
+ wtapng_block_t wblock;
+
+
+ /* we don't know the byte swapping of the file yet */
+ pn.byte_swapped = FALSE;
+
+
+ /* we don't expect any packet blocks yet */
+ wblock.frame_buffer = NULL;
+ wblock.pseudo_header = NULL;
+
+ /* read first block */
+ bytes_read = pcapng_read_block(wth->fh, &pn, &wblock, err, err_info);
+ if (bytes_read <= 0) {
+ *err = file_error(wth->fh);
+ g_warning("pcapng_open_new: couldn't read first SHB");
+ if (*err != 0)
+ return -1;
+ return 0;
+ }
+
+ wth->data_offset += bytes_read;
+
+ /* first block must be a "Section Header Block" */
+ if(wblock.type != 0x0A0D0D0A) {
+ g_warning("pcapng_open_new: first block type %u not SHB", wblock.type);
+ return 0;
+ }
+
+
+ /* read second block */
+ bytes_read = pcapng_read_block(wth->fh, &pn, &wblock, err, err_info);
+ if (bytes_read <= 0) {
+ *err = file_error(wth->fh);
+ g_warning("pcapng_open_new: couldn't read IDB");
+ if (*err != 0)
+ return -1;
+ return 0;
+ }
+
+ wth->data_offset += bytes_read;
+
+ /* second block must be an "Interface Description Block" */
+ if(wblock.type != 1) {
+ g_warning("pcapng_open_new: second block type %u not IDB", wblock.type);
+ return 0;
+ }
+
+ /* read "Interface Description Block" specific settings */
+ wth->file_encap = wblock.data.if_descr.link_type;
+ wth->snapshot_length = wblock.data.if_descr.snap_len;
+
+
+ /* Seems, this is a pcapng file */
+ wth->capture.pcapng = g_malloc(sizeof(pcapng_t));
+ *wth->capture.pcapng = pn;
+
+ wth->subtype_read = pcapng_read;
+ wth->subtype_seek_read = pcapng_seek_read;
+ wth->subtype_close = pcapng_close;
+
+ wth->file_type = WTAP_FILE_PCAPNG;
+ wth->tsprecision = WTAP_FILE_TSPREC_USEC; /* default is usec, might be overwritten with if_tsaccur option */
+
+ return 1;
+}
+
+
+/* classic wtap: read packet */
+static gboolean
+pcapng_read(wtap *wth, int *err, gchar **err_info,
+ gint64 *data_offset)
+{
+ int bytes_read;
+ wtapng_block_t wblock;
+
+
+ *data_offset = wth->data_offset;
+
+ /* XXX - this probably won't work well with unlimited / per packet snapshot length */
+ buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
+
+ wblock.frame_buffer = buffer_start_ptr(wth->frame_buffer);
+ wblock.pseudo_header = &wth->pseudo_header;
+
+ /* read next block */
+ bytes_read = pcapng_read_block(wth->fh, wth->capture.pcapng, &wblock, err, err_info);
+ if (bytes_read <= 0) {
+ *err = file_error(wth->fh);
+ /*g_warning("pcapng_read: couldn't read packet block");*/
+ if (*err != 0)
+ return -1;
+ return 0;
+ }
+
+ /* block must be a "Packet Block" or an "Enhanced Packet Block" */
+ if(wblock.type != 0x00000002 && wblock.type != 0x00000006) {
+ g_warning("pcapng_read: block type 0x%x not PB/EPB", wblock.type);
+ return 0;
+ }
+
+ if(bytes_read > 0) {
+ wth->phdr.caplen = wblock.data.packet.cap_len;
+ wth->phdr.len = wblock.data.packet.packet_len;
+ wth->phdr.ts.secs = wblock.data.packet.ts_high;
+ wth->phdr.ts.nsecs = wblock.data.packet.ts_low; /* convert here? */
+
+ /*g_warning("Read length: %u Packet length: %u", bytes_read, wth->phdr.caplen);*/
+ wth->data_offset += bytes_read;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/* classic wtap: seek to file position and read packet */
+static gboolean
+pcapng_seek_read(wtap *wth, gint64 seek_off,
+ union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
+ int *err, gchar **err_info)
+{
+ guint64 bytes_read64;
+ int bytes_read;
+ wtapng_block_t wblock;
+
+
+ /* seek to the right file position */
+ bytes_read64 = file_seek(wth->random_fh, seek_off, SEEK_SET, err);
+ if (bytes_read64 <= 0) {
+ return FALSE; /* Seek error */
+ }
+
+ wblock.frame_buffer = pd;
+ wblock.pseudo_header = pseudo_header;
+
+ /* read the block */
+ bytes_read = pcapng_read_block(wth->random_fh, wth->capture.pcapng, &wblock, err, err_info);
+ if (bytes_read <= 0) {
+ *err = file_error(wth->fh);
+ g_warning("pcapng_seek_read: couldn't read packet block");
+ return FALSE;
+ }
+
+ /* block must be a "Packet Block" or an "Enhanced Packet Block" */
+ if(wblock.type != 0x00000002 && wblock.type != 0x00000006) {
+ g_warning("pcapng_seek_read: block type %u not PB/EPB", wblock.type);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* classic wtap: close capture file */
+static void
+pcapng_close(wtap *wth)
+{
+ g_free(wth->capture.pcapng);
+}
+
+
+
+static gboolean
+pcapng_write_section_header_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
+{
+ pcapng_block_header_t bh;
+ pcapng_section_header_block_t shb;
+ size_t nwritten;
+
+
+ /* write block header */
+ bh.block_type = wblock->type;
+ bh.block_total_length = sizeof(bh) + sizeof(shb) /* + options */ + 4;
+
+ nwritten = wtap_dump_file_write(wdh, &bh, sizeof bh);
+ if (nwritten != sizeof bh) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof bh;
+
+ /* write block fixed content */
+ /* XXX - get these values from wblock? */
+ shb.magic = 0x1A2B3C4D;
+ shb.version_major = 1;
+ shb.version_minor = 0;
+ shb.section_length = -1;
+
+ nwritten = wtap_dump_file_write(wdh, &shb, sizeof shb);
+ if (nwritten != sizeof shb) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof shb;
+
+ /* XXX - write (optional) block options */
+
+ /* write block footer */
+ nwritten = wtap_dump_file_write(wdh, &bh.block_total_length, sizeof bh.block_total_length);
+ if (nwritten != sizeof bh.block_total_length) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof bh.block_total_length;
+
+ return TRUE;
+}
+
+
+
+static gboolean
+pcapng_write_if_descr_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
+{
+ pcapng_block_header_t bh;
+ pcapng_interface_description_block_t idb;
+ size_t nwritten;
+
+
+ /* write block header */
+ bh.block_type = wblock->type;
+ bh.block_total_length = sizeof(bh) + sizeof(idb) /* + options */ + 4;
+
+ nwritten = wtap_dump_file_write(wdh, &bh, sizeof bh);
+ if (nwritten != sizeof bh) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof bh;
+
+ /* write block fixed content */
+ idb.linktype = wblock->data.if_descr.link_type;
+ idb.reserved = 0;
+ idb.snaplen = wblock->data.if_descr.snap_len;
+
+ nwritten = wtap_dump_file_write(wdh, &idb, sizeof idb);
+ if (nwritten != sizeof idb) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof idb;
+
+ /* XXX - write (optional) block options */
+
+ /* write block footer */
+ nwritten = wtap_dump_file_write(wdh, &bh.block_total_length, sizeof bh.block_total_length);
+ if (nwritten != sizeof bh.block_total_length) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof bh.block_total_length;
+
+ return TRUE;
+}
+
+
+static gboolean
+pcapng_write_packet_block(wtap_dumper *wdh, wtapng_block_t *wblock, int *err)
+{
+ pcapng_block_header_t bh;
+ pcapng_enhanced_packet_block_t epb;
+ size_t nwritten;
+ guint32 zero_pad = 0;
+
+
+ guint32 cap_pad_len = 0;
+ if (wblock->data.packet.cap_len % 4) {
+ cap_pad_len += 4 - (wblock->data.packet.cap_len % 4);
+ }
+
+ /* write (enhanced) packet block header */
+ bh.block_type = wblock->type;
+ bh.block_total_length = sizeof(bh) + sizeof(epb) /* + pseudo header */ + wblock->data.packet.cap_len + cap_pad_len /* + options */ + 4;
+
+ nwritten = wtap_dump_file_write(wdh, &bh, sizeof bh);
+ if (nwritten != sizeof bh) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof bh;
+
+ /* write block fixed content */
+ epb.interface_id = 1; /* XXX */
+ epb.timestamp_high = wblock->data.packet.ts_high;
+ epb.timestamp_low = wblock->data.packet.ts_low;
+ epb.captured_len = wblock->data.packet.cap_len;
+ epb.packet_len = wblock->data.packet.packet_len;
+
+ nwritten = wtap_dump_file_write(wdh, &epb, sizeof epb);
+ if (nwritten != sizeof epb) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof epb;
+
+ /* XXX - write pseudo header */
+
+ /* write packet data */
+ nwritten = wtap_dump_file_write(wdh, wblock->frame_buffer, wblock->data.packet.cap_len);
+ if (nwritten != wblock->data.packet.cap_len) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += wblock->data.packet.cap_len;
+
+ /* write padding (if any) */
+ if(cap_pad_len != 0) {
+ nwritten = wtap_dump_file_write(wdh, &zero_pad, cap_pad_len);
+ if (nwritten != cap_pad_len) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += cap_pad_len;
+ }
+
+ /* XXX - write (optional) block options */
+
+ /* write block footer */
+ nwritten = wtap_dump_file_write(wdh, &bh.block_total_length, sizeof bh.block_total_length);
+ if (nwritten != sizeof bh.block_total_length) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += sizeof bh.block_total_length;
+
+ return TRUE;
+}
+
+
+static gboolean
+pcapng_write_block(wtap_dumper *wdh, /*pcapng_t *pn, */wtapng_block_t *wblock, int *err)
+{
+ switch(wblock->type) {
+ case(0x0A0D0D0A):
+ return pcapng_write_section_header_block(wdh, wblock, err);
+ break;
+ case(1):
+ return pcapng_write_if_descr_block(wdh, wblock, err);
+ break;
+ case(2):
+ return FALSE;
+ /* XXX - currently unsupported */
+ /*return pcapng_read_packet_block(wdd, wblock, err);*/
+ break;
+ case(6):
+ return pcapng_write_packet_block(wdh, wblock, err);
+ break;
+ default:
+ g_warning("Unknown block_type: 0x%x", wblock->type);
+ return FALSE;
+ }
+}
+
+
+static gboolean pcapng_dump(wtap_dumper *wdh,
+ const struct wtap_pkthdr *phdr,
+ const union wtap_pseudo_header *pseudo_header _U_,
+ const guchar *pd, int *err)
+{
+ wtapng_block_t wblock;
+
+ wblock.frame_buffer = pd;
+ wblock.pseudo_header = pseudo_header;
+
+ /* write the (enhanced) packet block */
+ wblock.type = 0x000006;
+
+ wblock.data.packet.ts_high = (guint32) phdr->ts.secs;
+ wblock.data.packet.ts_low = phdr->ts.nsecs; /* XXX - convert */
+ wblock.data.packet.cap_len = phdr->caplen;
+ wblock.data.packet.packet_len = phdr->len;
+
+ /* currently unused */
+ wblock.data.packet.drop_count = -1;
+ wblock.data.packet.opt_comment = NULL;
+
+ if (!pcapng_write_block(wdh, &wblock, err)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
+ failure */
+gboolean
+pcapng_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err)
+{
+ wtapng_block_t wblock;
+
+ wblock.frame_buffer = NULL;
+ wblock.pseudo_header = NULL;
+
+
+ /* This is a pcapng file */
+ wdh->subtype_write = pcapng_dump;
+ wdh->subtype_close = NULL;
+
+ /* write the section header block */
+ wblock.type = 0x0A0D0D0A;
+ wblock.data.section.section_length = -1;
+
+ /* XXX - options unused */
+ wblock.data.section.opt_comment = NULL;
+ wblock.data.section.shb_hardware = NULL;
+ wblock.data.section.shb_os = NULL;
+ wblock.data.section.shb_user_appl = NULL;
+
+ if (!pcapng_write_block(wdh, &wblock, err)) {
+ return FALSE;
+ }
+
+ /* write the interface description block */
+ wblock.type = 0x00000001;
+ wblock.data.if_descr.link_type = wdh->encap;
+ wblock.data.if_descr.snap_len = wdh->snaplen;
+
+ /* XXX - options unused */
+ wblock.data.if_descr.if_speed = -1;
+ wblock.data.if_descr.if_tsaccur = 6; /* default: usec */
+ wblock.data.if_descr.if_os = NULL;
+ wblock.data.if_descr.if_fcslen = -1;
+
+ if (!pcapng_write_block(wdh, &wblock, err)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Returns 0 if we could write the specified encapsulation type,
+ an error indication otherwise. */
+int pcapng_dump_can_write_encap(int encap)
+{
+ /* Per-packet encapsulations aren't supported. */
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ /* XXX - for now we only support Ethernet */
+ if (encap != WTAP_ENCAP_ETHERNET)
+ return WTAP_ERR_UNSUPPORTED_ENCAP;
+
+ return 0;
+}
+
diff --git a/wiretap/pcapng.h b/wiretap/pcapng.h new file mode 100644 index 0000000000..5819db0781 --- /dev/null +++ b/wiretap/pcapng.h @@ -0,0 +1,30 @@ +/* pcapng.h
+ *
+ * $Id: pcapng.h 22591 2007-08-22 19:38:49Z morriss $
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * 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_PCAPNG_H__
+#define __W_PCAPNG_H__
+
+int pcapng_open(wtap *wth, int *err, gchar **err_info);
+gboolean pcapng_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err);
+int pcapng_dump_can_write_encap(int encap);
+
+#endif
diff --git a/wiretap/wtap-int.h b/wiretap/wtap-int.h index a5afdceb1f..4a0bd848f5 100644 --- a/wiretap/wtap-int.h +++ b/wiretap/wtap-int.h @@ -97,6 +97,12 @@ typedef struct { } libpcap_t; typedef struct { + gboolean byte_swapped; + guint16 version_major; + guint16 version_minor; +} pcapng_t; + +typedef struct { time_t start_secs; guint32 start_usecs; guint8 version_major; @@ -180,6 +186,7 @@ struct wtap { catapult_dct2000_t *catapult_dct2000; mpeg_t *mpeg; void *generic; + pcapng_t *pcapng; } capture; subtype_read_func subtype_read; diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 2c0df52b26..e19f2a3f36 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -252,6 +252,7 @@ extern "C" { #define WTAP_FILE_K12TEXT 47 #define WTAP_FILE_NETSCREEN 48 #define WTAP_FILE_COMMVIEW 49 +#define WTAP_FILE_PCAPNG 50 #define WTAP_NUM_FILE_TYPES wtap_get_num_file_types() |