diff options
author | Stephen Fisher <steve@stephen-fisher.com> | 2008-01-13 21:10:09 +0000 |
---|---|---|
committer | Stephen Fisher <steve@stephen-fisher.com> | 2008-01-13 21:10:09 +0000 |
commit | a98ff5a0175d9afa596d92e48a30568526ae655f (patch) | |
tree | 863c5822290108068e027515aaa4518f6205658b | |
parent | c352fb38329c6be9947887b9a6756e13705f21fa (diff) | |
download | wireshark-a98ff5a0175d9afa596d92e48a30568526ae655f.tar.gz wireshark-a98ff5a0175d9afa596d92e48a30568526ae655f.tar.bz2 wireshark-a98ff5a0175d9afa596d92e48a30568526ae655f.zip |
Add svn:eol-style native and svn:keywords Id
svn path=/trunk/; revision=24081
-rw-r--r-- | wiretap/pcapng.c | 1974 | ||||
-rw-r--r-- | wiretap/pcapng.h | 60 |
2 files changed, 1017 insertions, 1017 deletions
diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 11d5b62b89..ea60859074 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -1,987 +1,987 @@ -/* 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 _U_)
-{
- 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 _U_)
-{
- 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) {
-#if 0
- g_warning("pcapng_read_if_descr_block: snapshot length %u unrealistic",
- pcapng_read_if_descr_block);
-#endif
- /*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 _U_)
-{
- 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 = -1; /* XXX - Init this differently? */
- 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");
- *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 _U_,
- 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;
-}
-
+/* pcapng.c + * + * $Id$ + * + * 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 _U_) +{ + 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 _U_) +{ + 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) { +#if 0 + g_warning("pcapng_read_if_descr_block: snapshot length %u unrealistic", + pcapng_read_if_descr_block); +#endif + /*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 _U_) +{ + 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 = -1; /* XXX - Init this differently? */ + 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"); + *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 _U_, + 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 index 5819db0781..b5b037ebd4 100644 --- a/wiretap/pcapng.h +++ b/wiretap/pcapng.h @@ -1,30 +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
+/* pcapng.h + * + * $Id$ + * + * 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 |