From Tom Brezinski - fix for bug 5869:

This patch incorporates the following fixes from the patch attached to
bug 5671 with changes as noted below:

1.) Files where the packet header and packet data are noncontiguous are
handled improperly, resulting in read misalignment and ultimately the
error message, "Observer: bad record: Invalid magic number 0xXXXXXXXX."
This bug is caused by not obeying the packet_entry_header.offset_to_frame
field.

2.) Daylight savings time is not properly accounted for in files using
local time encoding.

3.) As of Observer/GigaStor v13.10 (bug 5671 incorrectly stated v14),
timestamps in the file format changed from local time encoding to GMT
encoding.  Wiretap has been changed to support reading both formats. 
Patch submitted with bug 5671 added a separate file type to allow
writing local format.  This patch does not add the separate file type
and always writes GMT.

4.) The wtap_dumper.bytes_dumped field is not being properly incremented
as data is written to files.

This patch also incorporates the following additional enhancements /
fixes not in bug 5671:

1.) Support for reading BFR files which contain Fibre Channel captures. 
Test file Fibre_Channel_Capture.bfr attached.

2.) Support for modified file header used in upcoming v15.  New header
file format takes an unused byte from the version string to allow for a
larger offset to the first packet to be specified.  Test file
V15_Lrg_Hdr_Test.bfr is attached, it is also a fuzz test as the number
of TLV items given in the header is less then the actual.

3.) It was found that if the number of TLV items given in the header was
larger then present it would fail to open the file.  Test file
V9_Num_TLVs_Too_Big.bfr is attached.

svn path=/trunk/; revision=36970
This commit is contained in:
Guy Harris 2011-05-03 05:26:10 +00:00
parent 7eb4723184
commit c0dc916adc
5 changed files with 442 additions and 220 deletions

View File

@ -3448,6 +3448,7 @@ RSA <ryazanov.s.a [AT] gmail.com>
Juliusz Chroboczek <jch [AT] pps.jussieu.fr> Juliusz Chroboczek <jch [AT] pps.jussieu.fr>
Vladimir Kazansky <vovjo [AT] yandex.ru> Vladimir Kazansky <vovjo [AT] yandex.ru>
Peter Paluch <peter.paluch [AT] fri.uniza.sk> Peter Paluch <peter.paluch [AT] fri.uniza.sk>
Tom Brezinski <tombr [AT] netinst.com>
Dan Lasley <dlasley[AT]promus.com> gave permission for his Dan Lasley <dlasley[AT]promus.com> gave permission for his
dumpit() hex-dump routine to be used. dumpit() hex-dump routine to be used.

View File

@ -535,8 +535,8 @@ static const struct file_type_info dump_open_table_base[] = {
{ "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "*.cap", ".cap", TRUE, FALSE, { "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "*.cap", ".cap", TRUE, FALSE,
netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 }, netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
/* WTAP_FILE_NETWORK_INSTRUMENTS_V9 */ /* WTAP_FILE_NETWORK_INSTRUMENTS */
{ "Network Instruments Observer (V9)", "niobserverv9", "*.bfr", ".bfr", FALSE, FALSE, { "Network Instruments Observer", "niobserverv", "*.bfr", ".bfr", FALSE, FALSE,
network_instruments_dump_can_write_encap, network_instruments_dump_open }, network_instruments_dump_can_write_encap, network_instruments_dump_open },
/* WTAP_FILE_LANALYZER */ /* WTAP_FILE_LANALYZER */

View File

@ -3,7 +3,7 @@
*/ */
/*************************************************************************** /***************************************************************************
NetworkInstruments.c - description network_instruments.c - description
------------------- -------------------
begin : Wed Oct 29 2003 begin : Wed Oct 29 2003
copyright : (C) 2003 by root copyright : (C) 2003 by root
@ -31,61 +31,73 @@
#include "buffer.h" #include "buffer.h"
#include "network_instruments.h" #include "network_instruments.h"
static const char network_instruments_magic[] = {"ObserverPktBufferVersion=09.00"}; static const char network_instruments_magic[] = {"ObserverPktBufferVersion=15.00"};
static const int true_magic_length = 17; static const int true_magic_length = 17;
static const guint32 observer_packet_magic = 0x88888888; static const guint32 observer_packet_magic = 0x88888888;
static const int observer_encap[] = { /*
WTAP_ENCAP_ETHERNET, * This structure is used to keep state when writing files. An instance is
WTAP_ENCAP_TOKEN_RING * allocated for each file, and its address is stored in the wtap_dumper.priv
}; * pointer field.
#define NUM_OBSERVER_ENCAPS (sizeof observer_encap / sizeof observer_encap[0]) */
typedef struct {
static const int from_wtap_encap[] = { guint64 packet_count;
OBSERVER_UNDEFINED, guint8 network_type;
OBSERVER_ETHERNET, guint32 time_format;
OBSERVER_TOKENRING, } observer_dump_private_state;
};
#define NUM_FROM_WTAP_ENCAPS (sizeof from_wtap_encap / sizeof observer_encap[0])
#define CAPTUREFILE_HEADER_SIZE sizeof(capture_file_header)
/* /*
* The time in Observer files is in nanoseconds since midnight, January 1, * Some time offsets are calculated in advance here, when the first Observer
* 2000, 00:00:00 local time. * file is opened for reading or writing, and are then used to adjust frame
* timestamps as they are read or written.
* *
* We want the seconds portion to be seconds since midnight, January 1, * The Wiretap API expects timestamps in nanoseconds relative to
* 1970, 00:00:00 GMT. * January 1, 1970, 00:00:00 GMT (the Wiretap epoch).
* *
* To do that, we add the number of seconds between midnight, January 1, * Observer versions before 13.10 encode frame timestamps in nanoseconds
* 2000, 00:00:00 local time and midnight, January 1, 1970, 00:00:00 GMT. * relative to January 1, 2000, 00:00:00 local time (the Observer epoch).
* (That gets the wrong answer if the time zone is being read in a different * Versions 13.10 and later switch over to GMT encoding. Which encoding was used
* time zone, but there's not much we can do about that.) * when saving the file is identified via the time format TLV following
* the file header.
*
* Unfortunately, even though Observer versions before 13.10 saved in local
* time, they didn't include the timezone from which the frames were captured,
* so converting to GMT correctly from all timezones is impossible. So an
* assumption is made that the file is being read from within the same timezone
* that it was written.
*
* All code herein is normalized to versions 13.10 and later, special casing for
* versions earlier. In other words, timestamps are worked with as if
* they are GMT-encoded, and adjustments from local time are made only if
* the source file warrants it.
*
* All destination files are saved in GMT format.
*/ */
static gboolean have_time_offset; static const time_t ansi_to_observer_epoch_offset = 946684800;
static time_t seconds1970to2000; static time_t gmt_to_localtime_offset = (time_t) -1;
static void init_time_offset(void) static void init_gmt_to_localtime_offset(void)
{ {
if (!have_time_offset) { if (gmt_to_localtime_offset == (time_t) -1) {
struct tm midnight_2000_01_01; time_t ansi_epoch_plus_one_day = 86400;
struct tm gmt_tm;
/* struct tm local_tm;
* Get the number of seconds between midnight, January 1,
* 2000, 00:00:00 local time - that's just the UNIX /*
* time stamp for 2000-01-01 00:00:00 local time. * Compute the local time zone offset as the number of seconds west
*/ * of GMT. There's no obvious cross-platform API for querying this
midnight_2000_01_01.tm_year = 2000 - 1900; * directly. As a workaround, GMT and local tm structures are populated
midnight_2000_01_01.tm_mon = 0; * relative to the ANSI time_t epoch (plus one day to ensure that
midnight_2000_01_01.tm_mday = 1; * local time stays after 1970/1/1 00:00:00). They are then converted
midnight_2000_01_01.tm_hour = 0; * back to time_t as if they were both local times, resulting in the
midnight_2000_01_01.tm_min = 0; * time zone offset being the difference between them.
midnight_2000_01_01.tm_sec = 0; */
midnight_2000_01_01.tm_isdst = -1; gmt_tm = *gmtime(&ansi_epoch_plus_one_day);
seconds1970to2000 = mktime(&midnight_2000_01_01); local_tm = *localtime(&ansi_epoch_plus_one_day);
have_time_offset = TRUE; local_tm.tm_isdst = 0;
} gmt_to_localtime_offset = mktime(&gmt_tm) - mktime(&local_tm);
}
} }
static gboolean observer_read(wtap *wth, int *err, gchar **err_info, static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
@ -95,12 +107,14 @@ static gboolean observer_seek_read(wtap *wth, gint64 seek_off,
int *err, gchar **err_info); int *err, gchar **err_info);
static int read_packet_header(FILE_T fh, packet_entry_header *packet_header, static int read_packet_header(FILE_T fh, packet_entry_header *packet_header,
int *err, gchar **err_info); int *err, gchar **err_info);
static gboolean read_packet_data(FILE_T fh, int offset_to_frame, int offset, static int read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header,
guint8 *pd, int length, int *err, char **err_info); guint8 *pd, int length, int *err, char **err_info);
static gboolean skip_to_next_packet(wtap *wth, int offset, static gboolean skip_to_next_packet(wtap *wth, int offset_to_next_packet,
int offset_to_next_packet, int *err, char **err_info); int current_offset_from_packet_header, int *err, char **err_info);
static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err); const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
static gint observer_to_wtap_encap(int observer_encap);
static gint wtap_to_observer_encap(int wtap_encap);
int network_instruments_open(wtap *wth, int *err, gchar **err_info) int network_instruments_open(wtap *wth, int *err, gchar **err_info)
{ {
@ -110,7 +124,9 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
guint i; guint i;
tlv_header tlvh; tlv_header tlvh;
int seek_increment; int seek_increment;
int header_offset;
packet_entry_header packet_header; packet_entry_header packet_header;
observer_dump_private_state * private_state = NULL;
errno = WTAP_ERR_CANT_READ; errno = WTAP_ERR_CANT_READ;
offset = 0; offset = 0;
@ -124,21 +140,28 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
return 0; return 0;
} }
offset += bytes_read; offset += bytes_read;
CAPTURE_FILE_HEADER_FROM_LE_IN_PLACE(file_header);
/* check the magic number */ /* check if version info is present */
if (memcmp(file_header.observer_version, network_instruments_magic, true_magic_length)!=0) { if (memcmp(file_header.observer_version, network_instruments_magic, true_magic_length)!=0) {
return 0; return 0;
} }
/* check the version */ /* initialize the private state */
if (strncmp(network_instruments_magic, file_header.observer_version, 30)!=0) { private_state = (observer_dump_private_state *) g_malloc(sizeof(observer_dump_private_state));
*err = WTAP_ERR_UNSUPPORTED_ENCAP; private_state->time_format = TIME_INFO_LOCAL;
*err_info = g_strdup_printf("Observer: unsupported file version %s", file_header.observer_version); wth->priv = (void *) private_state;
return -1;
} /* get the location of the first packet */
/* v15 and newer uses high byte offset, in previous versions it will be 0 */
header_offset = file_header.offset_to_first_packet + ((int)(file_header.offset_to_first_packet_high_byte)<<16);
/* process extra information */ /* process extra information */
for (i = 0; i < file_header.number_of_information_elements; i++) { for (i = 0; i < file_header.number_of_information_elements; i++) {
/* for safety break if we've reached the first packet */
if (offset >= header_offset)
break;
/* read the TLV header */ /* read the TLV header */
bytes_read = file_read(&tlvh, sizeof tlvh, wth->fh); bytes_read = file_read(&tlvh, sizeof tlvh, wth->fh);
if (bytes_read != sizeof tlvh) { if (bytes_read != sizeof tlvh) {
@ -148,8 +171,8 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
return -1; return -1;
} }
offset += bytes_read; offset += bytes_read;
TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
tlvh.length = GUINT16_FROM_LE(tlvh.length);
if (tlvh.length < sizeof tlvh) { if (tlvh.length < sizeof tlvh) {
*err = WTAP_ERR_BAD_RECORD; *err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)", *err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)",
@ -157,25 +180,37 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
return -1; return -1;
} }
/* skip the TLV data */ /* process (or skip over) the current TLV */
seek_increment = tlvh.length - (int)sizeof tlvh; switch (tlvh.type) {
if (seek_increment > 0) { case INFORMATION_TYPE_TIME_INFO:
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1) bytes_read = file_read(&private_state->time_format, sizeof private_state->time_format, wth->fh);
if (bytes_read != sizeof private_state->time_format) {
*err = file_error(wth->fh, err_info);
if(*err == 0)
*err = WTAP_ERR_SHORT_READ;
return -1; return -1;
}
private_state->time_format = GUINT32_FROM_LE(private_state->time_format);
offset += bytes_read;
break;
default:
seek_increment = tlvh.length - (int)sizeof tlvh;
if (seek_increment > 0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
return -1;
}
offset += seek_increment;
} }
offset += seek_increment;
} }
/* get to the first packet */ /* get to the first packet */
file_header.offset_to_first_packet = if (header_offset < offset) {
GUINT16_FROM_LE(file_header.offset_to_first_packet);
if (file_header.offset_to_first_packet < offset) {
*err = WTAP_ERR_BAD_RECORD; *err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (offset to first packet %d < %d)", *err_info = g_strdup_printf("Observer: bad record (offset to first packet %d < %d)",
file_header.offset_to_first_packet, offset); header_offset, offset);
return FALSE; return FALSE;
} }
seek_increment = file_header.offset_to_first_packet - offset; seek_increment = header_offset - offset;
if (seek_increment > 0) { if (seek_increment > 0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1) if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
return -1; return -1;
@ -189,9 +224,9 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
return -1; return -1;
return 0; return 0;
} }
PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(packet_header);
/* check the packet's magic number; the magic number is all 8's, /* check the packet's magic number */
so the byte order doesn't matter */
if (packet_header.packet_magic != observer_packet_magic) { if (packet_header.packet_magic != observer_packet_magic) {
*err = WTAP_ERR_UNSUPPORTED_ENCAP; *err = WTAP_ERR_UNSUPPORTED_ENCAP;
*err_info = g_strdup_printf("Observer: unsupported packet version %ul", packet_header.packet_magic); *err_info = g_strdup_printf("Observer: unsupported packet version %ul", packet_header.packet_magic);
@ -199,30 +234,31 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
} }
/* check the data link type */ /* check the data link type */
if (packet_header.network_type >= NUM_OBSERVER_ENCAPS) { if (observer_to_wtap_encap(packet_header.network_type) == WTAP_ENCAP_UNKNOWN) {
*err = WTAP_ERR_UNSUPPORTED_ENCAP; *err = WTAP_ERR_UNSUPPORTED_ENCAP;
*err_info = g_strdup_printf("Observer: network type %u unknown or unsupported", packet_header.network_type); *err_info = g_strdup_printf("Observer: network type %u unknown or unsupported", packet_header.network_type);
return -1; return -1;
} }
wth->file_encap = observer_encap[packet_header.network_type]; wth->file_encap = observer_to_wtap_encap(packet_header.network_type);
wth->file_type = WTAP_FILE_NETWORK_INSTRUMENTS_V9;
/* set up the rest of the capture parameters */ /* set up the rest of the capture parameters */
private_state->packet_count = 0;
private_state->network_type = wtap_to_observer_encap(wth->file_encap);
wth->subtype_read = observer_read; wth->subtype_read = observer_read;
wth->subtype_seek_read = observer_seek_read; wth->subtype_seek_read = observer_seek_read;
wth->subtype_close = NULL; wth->subtype_close = NULL;
wth->subtype_sequential_close = NULL; wth->subtype_sequential_close = NULL;
wth->snapshot_length = 0; /* not available in header */ wth->snapshot_length = 0; /* not available in header */
wth->tsprecision = WTAP_FILE_TSPREC_NSEC; wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
wth->file_type = WTAP_FILE_NETWORK_INSTRUMENTS;
/* reset the pointer to the first packet */ /* reset the pointer to the first packet */
if (file_seek(wth->fh, file_header.offset_to_first_packet, SEEK_SET, if (file_seek(wth->fh, header_offset, SEEK_SET,
err) == -1) err) == -1)
return -1; return -1;
wth->data_offset = file_header.offset_to_first_packet; wth->data_offset = header_offset;
init_time_offset(); init_gmt_to_localtime_offset();
return 1; return 1;
} }
@ -231,7 +267,8 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
static gboolean observer_read(wtap *wth, int *err, gchar **err_info, static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
gint64 *data_offset) gint64 *data_offset)
{ {
int offset; int bytes_consumed;
int offset_from_packet_header = 0;
packet_entry_header packet_header; packet_entry_header packet_header;
/* skip records other than data records */ /* skip records other than data records */
@ -239,20 +276,22 @@ static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
*data_offset = wth->data_offset; *data_offset = wth->data_offset;
/* process the packet header, including TLVs */ /* process the packet header, including TLVs */
offset = read_packet_header(wth->fh, &packet_header, err, bytes_consumed = read_packet_header(wth->fh, &packet_header, err,
err_info); err_info);
if (offset <= 0) if (bytes_consumed <= 0)
return FALSE; /* EOF or error */ return FALSE; /* EOF or error */
wth->data_offset += offset; wth->data_offset += bytes_consumed;
if (packet_header.packet_type == PACKET_TYPE_DATA_PACKET) if (packet_header.packet_type == PACKET_TYPE_DATA_PACKET)
break; break;
/* skip to next packet */ /* skip to next packet */
if (!skip_to_next_packet(wth, offset, offset_from_packet_header = (int) (wth->data_offset - *data_offset);
packet_header.offset_to_next_packet, err, err_info)) if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
return FALSE; /* EOF or error */ offset_from_packet_header, err, err_info)) {
return FALSE; /* EOF or error */
}
} }
/* neglect frame markers for wiretap */ /* neglect frame markers for wiretap */
@ -264,16 +303,43 @@ static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
} }
/* set the wiretap packet header fields */ /* set the wiretap packet header fields */
wth->phdr.pkt_encap = observer_encap[packet_header.network_type]; wth->phdr.pkt_encap = observer_to_wtap_encap(packet_header.network_type);
wth->phdr.len = packet_header.network_size - 4; if(wth->file_encap == WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS) {
wth->phdr.caplen = MIN(packet_header.captured_size, wth->phdr.len); wth->phdr.len = packet_header.network_size;
wth->phdr.ts.secs = wth->phdr.caplen = packet_header.captured_size;
(time_t) (packet_header.nano_seconds_since_2000/1000000000 + seconds1970to2000); } else {
wth->phdr.ts.nsecs = (int) (packet_header.nano_seconds_since_2000%1000000000); wth->phdr.len = packet_header.network_size - 4;
wth->phdr.caplen = MIN(packet_header.captured_size, wth->phdr.len);
}
/* set the wiretap timestamp, assuming for the moment that Observer encoded it in GMT */
wth->phdr.ts.secs = (time_t) ((packet_header.nano_seconds_since_2000 / 1000000000) + ansi_to_observer_epoch_offset);
wth->phdr.ts.nsecs = (int) (packet_header.nano_seconds_since_2000 % 1000000000);
/* adjust to local time, if necessary, also accounting for DST if the frame
was captured while it was in effect */
if (((observer_dump_private_state*)wth->priv)->time_format == TIME_INFO_LOCAL)
{
struct tm daylight_tm;
struct tm standard_tm;
time_t dst_offset;
/* the Observer timestamp was encoded as local time, so add a
correction from local time to GMT */
wth->phdr.ts.secs += gmt_to_localtime_offset;
/* perform a DST adjustment if necessary */
standard_tm = *localtime(&wth->phdr.ts.secs);
if (standard_tm.tm_isdst > 0) {
daylight_tm = standard_tm;
standard_tm.tm_isdst = 0;
dst_offset = mktime(&standard_tm) - mktime(&daylight_tm);
wth->phdr.ts.secs -= dst_offset;
}
}
/* update the pseudo header */ /* update the pseudo header */
switch (wth->file_encap) { switch (wth->file_encap) {
case WTAP_ENCAP_ETHERNET: case WTAP_ENCAP_ETHERNET:
/* There is no FCS in the frame */ /* There is no FCS in the frame */
wth->pseudo_header.eth.fcs_len = 0; wth->pseudo_header.eth.fcs_len = 0;
@ -283,20 +349,24 @@ static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
/* set-up the packet buffer */ /* set-up the packet buffer */
buffer_assure_space(wth->frame_buffer, packet_header.captured_size); buffer_assure_space(wth->frame_buffer, packet_header.captured_size);
/* read the frame data */ /* read the frame data */
if (!read_packet_data(wth->fh, packet_header.offset_to_frame, offset, offset_from_packet_header = (int) (wth->data_offset - *data_offset);
buffer_start_ptr(wth->frame_buffer), packet_header.captured_size, bytes_consumed = read_packet_data(wth->fh, packet_header.offset_to_frame,
err, err_info)) offset_from_packet_header, buffer_start_ptr(wth->frame_buffer),
return FALSE; packet_header.captured_size, err, err_info);
wth->data_offset += packet_header.captured_size; if (bytes_consumed < 0) {
offset += packet_header.captured_size; return FALSE;
}
wth->data_offset += bytes_consumed;
/* skip over any extra bytes following the frame data */ /* skip over any extra bytes following the frame data */
if (!skip_to_next_packet(wth, offset, packet_header.offset_to_next_packet, offset_from_packet_header = (int) (wth->data_offset - *data_offset);
err, err_info)) if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
return FALSE; offset_from_packet_header, err, err_info)) {
return FALSE;
}
return TRUE; return TRUE;
} }
/* Reads a packet at an offset. */ /* Reads a packet at an offset. */
@ -354,19 +424,7 @@ read_packet_header(FILE_T fh, packet_entry_header *packet_header, int *err,
return 0; /* EOF */ return 0; /* EOF */
} }
offset += bytes_read; offset += bytes_read;
PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(*packet_header);
/* swap all multi-byte fields immediately */
packet_header->packet_magic = GUINT32_FROM_LE(packet_header->packet_magic);
packet_header->network_speed = GUINT32_FROM_LE(packet_header->network_speed);
packet_header->captured_size = GUINT16_FROM_LE(packet_header->captured_size);
packet_header->network_size = GUINT16_FROM_LE(packet_header->network_size);
packet_header->offset_to_frame = GUINT16_FROM_LE(packet_header->offset_to_frame);
packet_header->offset_to_next_packet = GUINT16_FROM_LE(packet_header->offset_to_next_packet);
packet_header->errors = GUINT16_FROM_LE(packet_header->errors);
packet_header->reserved = GUINT16_FROM_LE(packet_header->reserved);
packet_header->packet_number = GUINT64_FROM_LE(packet_header->packet_number);
packet_header->original_packet_number = GUINT64_FROM_LE(packet_header->original_packet_number);
packet_header->nano_seconds_since_2000 = GUINT64_FROM_LE(packet_header->nano_seconds_since_2000);
/* check the packet's magic number */ /* check the packet's magic number */
if (packet_header->packet_magic != observer_packet_magic) { if (packet_header->packet_magic != observer_packet_magic) {
@ -404,8 +462,8 @@ read_packet_header(FILE_T fh, packet_entry_header *packet_header, int *err,
return -1; return -1;
} }
offset += bytes_read; offset += bytes_read;
TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
tlvh.length = GUINT16_FROM_LE(tlvh.length);
if (tlvh.length < sizeof tlvh) { if (tlvh.length < sizeof tlvh) {
*err = WTAP_ERR_BAD_RECORD; *err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)", *err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)",
@ -425,56 +483,62 @@ read_packet_header(FILE_T fh, packet_entry_header *packet_header, int *err,
return offset; return offset;
} }
static gboolean static int
read_packet_data(FILE_T fh, int offset_to_frame, int offset, guint8 *pd, read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header, guint8 *pd,
int length, int *err, char **err_info) int length, int *err, char **err_info)
{ {
int seek_increment; int seek_increment;
int bytes_consumed = 0;
/* get to the packet data */
if (offset_to_frame < offset) { /* validate offsets */
if (offset_to_frame < current_offset_from_packet_header) {
*err = WTAP_ERR_BAD_RECORD; *err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (offset to packet data %d < %d)", *err_info = g_strdup_printf("Observer: bad record (offset to packet data %d < %d)",
offset_to_frame, offset); offset_to_frame, current_offset_from_packet_header);
return FALSE; return -1;
}
seek_increment = offset_to_frame - offset;
if (seek_increment > 0) {
if (file_seek(fh, seek_increment, SEEK_CUR, err) == -1)
return FALSE;
} }
/* read in the packet */ /* skip to the packet data */
seek_increment = offset_to_frame - current_offset_from_packet_header;
if (seek_increment > 0) {
if (file_seek(fh, seek_increment, SEEK_CUR, err) == -1) {
return -1;
}
bytes_consumed += seek_increment;
}
/* read in the packet data */
wtap_file_read_expected_bytes(pd, length, fh, err, err_info); wtap_file_read_expected_bytes(pd, length, fh, err, err_info);
return TRUE; bytes_consumed += length;
return bytes_consumed;
} }
static gboolean static gboolean
skip_to_next_packet(wtap *wth, int offset, int offset_to_next_packet, int *err, skip_to_next_packet(wtap *wth, int offset_to_next_packet, int current_offset_from_packet_header, int *err,
char **err_info) char **err_info)
{ {
int seek_increment; int seek_increment;
if (offset_to_next_packet < offset) { /* validate offsets */
if (offset_to_next_packet < current_offset_from_packet_header) {
*err = WTAP_ERR_BAD_RECORD; *err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (offset to next packet %d < %d)", *err_info = g_strdup_printf("Observer: bad record (offset to next packet %d < %d)",
offset_to_next_packet, offset); offset_to_next_packet, current_offset_from_packet_header);
return FALSE; return FALSE;
} }
seek_increment = offset_to_next_packet - offset;
/* skip to the next packet header */
seek_increment = offset_to_next_packet - current_offset_from_packet_header;
if (seek_increment > 0) { if (seek_increment > 0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1) if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
return FALSE; return FALSE;
wth->data_offset += seek_increment;
} }
wth->data_offset += seek_increment;
return TRUE; return TRUE;
} }
typedef struct {
guint64 packet_count;
guint8 network_type;
} niobserver_dump_t;
/* Returns 0 if we could write the specified encapsulation type, /* Returns 0 if we could write the specified encapsulation type,
an error indication otherwise. */ an error indication otherwise. */
int network_instruments_dump_can_write_encap(int encap) int network_instruments_dump_can_write_encap(int encap)
@ -483,7 +547,7 @@ int network_instruments_dump_can_write_encap(int encap)
if (encap == WTAP_ENCAP_PER_PACKET) if (encap == WTAP_ENCAP_PER_PACKET)
return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED; return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
if (encap < 0 || (unsigned) encap >= NUM_FROM_WTAP_ENCAPS || from_wtap_encap[encap] == OBSERVER_UNDEFINED) if (encap < 0 || (wtap_to_observer_encap(encap) == OBSERVER_UNDEFINED))
return WTAP_ERR_UNSUPPORTED_ENCAP; return WTAP_ERR_UNSUPPORTED_ENCAP;
return 0; return 0;
@ -493,47 +557,92 @@ int network_instruments_dump_can_write_encap(int encap)
failure. */ failure. */
gboolean network_instruments_dump_open(wtap_dumper *wdh, int *err) gboolean network_instruments_dump_open(wtap_dumper *wdh, int *err)
{ {
capture_file_header file_header; observer_dump_private_state * private_state = NULL;
tlv_header comment_header; capture_file_header file_header;
char comment[64];
struct tm *current_time;
time_t system_time;
niobserver_dump_t *niobserver;
wdh->subtype_write = observer_dump; tlv_header comment_header;
tlv_time_info time_header;
char comment[64];
size_t comment_length;
struct tm * current_time;
time_t system_time;
niobserver = (niobserver_dump_t *)g_malloc(sizeof(niobserver_dump_t)); /* initialize the private state */
wdh->priv = (void *)niobserver; private_state = (observer_dump_private_state *) g_malloc(sizeof(observer_dump_private_state));
niobserver->packet_count = 0; private_state->packet_count = 0;
niobserver->network_type = from_wtap_encap[wdh->encap]; private_state->network_type = wtap_to_observer_encap(wdh->encap);
private_state->time_format = TIME_INFO_GMT;
/* populate the fields of wdh */
wdh->priv = (void *) private_state;
wdh->subtype_write = observer_dump;
/* create the file comment */ /* initialize the file header */
time(&system_time); memset(&file_header, 0x00, sizeof(file_header));
current_time = localtime(&system_time); g_strlcpy(file_header.observer_version, network_instruments_magic, 31);
memset(&comment, 0x00, sizeof(comment)); file_header.offset_to_first_packet = (guint16)sizeof(file_header);
g_snprintf(comment, 64, "This capture was saved from Wireshark on %s", asctime(current_time)); file_header.offset_to_first_packet_high_byte = 0;
/* create the file header */ /* create the file comment TLV */
memset(&file_header, 0x00, sizeof(capture_file_header)); {
g_strlcpy(file_header.observer_version, network_instruments_magic, 32); time(&system_time);
file_header.offset_to_first_packet = (guint16) (sizeof(capture_file_header) + sizeof(tlv_header) + strlen(comment)); current_time = localtime(&system_time);
file_header.offset_to_first_packet = GUINT16_TO_LE(file_header.offset_to_first_packet); memset(&comment, 0x00, sizeof(comment));
file_header.number_of_information_elements = 1; g_snprintf(comment, 64, "This capture was saved from Wireshark on %s", asctime(current_time));
if(!wtap_dump_file_write(wdh, &file_header, sizeof(capture_file_header), err)) comment_length = strlen(comment);
return FALSE;
/* create the comment entry */ comment_header.type = INFORMATION_TYPE_COMMENT;
comment_header.type = GUINT16_TO_LE(INFORMATION_TYPE_COMMENT); comment_header.length = (guint16) (sizeof(comment_header) + comment_length);
comment_header.length = (guint16) (sizeof(tlv_header) + strlen(comment));
comment_header.length = GUINT16_TO_LE(comment_header.length);
if(!wtap_dump_file_write(wdh, &comment_header, sizeof(tlv_header), err))
return FALSE;
if(!wtap_dump_file_write(wdh, &comment, strlen(comment), err))
return FALSE;
init_time_offset(); /* update the file header to account for the comment TLV */
file_header.number_of_information_elements++;
file_header.offset_to_first_packet += comment_header.length;
}
return TRUE; /* create the timestamp encoding TLV */
{
time_header.type = INFORMATION_TYPE_TIME_INFO;
time_header.length = (guint16) (sizeof(time_header));
time_header.time_format = TIME_INFO_GMT;
/* update the file header to account for the timestamp encoding TLV */
file_header.number_of_information_elements++;
file_header.offset_to_first_packet += time_header.length;
}
/* write the file header, swapping any multibyte fields first */
CAPTURE_FILE_HEADER_TO_LE_IN_PLACE(file_header);
if (!wtap_dump_file_write(wdh, &file_header, sizeof(file_header), err)) {
return FALSE;
}
wdh->bytes_dumped += sizeof(file_header);
/* write the comment TLV */
{
TLV_HEADER_TO_LE_IN_PLACE(comment_header);
if (!wtap_dump_file_write(wdh, &comment_header, sizeof(comment_header), err)) {
return FALSE;
}
wdh->bytes_dumped += sizeof(comment_header);
if (!wtap_dump_file_write(wdh, &comment, comment_length, err)) {
return FALSE;
}
wdh->bytes_dumped += comment_length;
}
/* write the time info TLV */
{
TLV_TIME_INFO_TO_LE_IN_PLACE(time_header);
if (!wtap_dump_file_write(wdh, &time_header, sizeof(time_header), err)) {
return FALSE;
}
wdh->bytes_dumped += sizeof(time_header);
}
init_gmt_to_localtime_offset();
return TRUE;
} }
/* Write a record for a packet to a dump file. /* Write a record for a packet to a dump file.
@ -542,41 +651,84 @@ static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
const union wtap_pseudo_header *pseudo_header _U_, const guchar *pd, const union wtap_pseudo_header *pseudo_header _U_, const guchar *pd,
int *err) int *err)
{ {
niobserver_dump_t *niobserver = (niobserver_dump_t *)wdh->priv; observer_dump_private_state * private_state = NULL;
packet_entry_header packet_header; packet_entry_header packet_header;
guint64 capture_nanoseconds; guint64 seconds_since_2000;
if (phdr->ts.secs < seconds1970to2000) { /* convert the number of seconds since epoch from ANSI-relative to
if (phdr->ts.secs < 0) Observer-relative */
capture_nanoseconds = 0; if (phdr->ts.secs < ansi_to_observer_epoch_offset) {
else if(phdr->ts.secs > (time_t) 0) {
capture_nanoseconds = phdr->ts.secs; seconds_since_2000 = phdr->ts.secs;
} else } else {
capture_nanoseconds = phdr->ts.secs - seconds1970to2000; seconds_since_2000 = (time_t) 0;
capture_nanoseconds = capture_nanoseconds*1000000000 + phdr->ts.nsecs; }
} else {
seconds_since_2000 = phdr->ts.secs - ansi_to_observer_epoch_offset;
}
memset(&packet_header, 0x00, sizeof(packet_entry_header)); /* populate the fields of the packet header */
packet_header.packet_magic = GUINT32_TO_LE(observer_packet_magic); private_state = (observer_dump_private_state *) wdh->priv;
packet_header.network_speed = GUINT32_TO_LE(1000000);
packet_header.captured_size = GUINT16_TO_LE((guint16)phdr->caplen);
packet_header.network_size = GUINT16_TO_LE((guint16)(phdr->len+4));
packet_header.offset_to_frame = GUINT16_TO_LE(sizeof(packet_entry_header));
packet_header.offset_to_next_packet = GUINT16_TO_LE(sizeof(packet_entry_header) + phdr->caplen);
packet_header.network_type = niobserver->network_type;
packet_header.flags = 0x00;
packet_header.number_of_information_elements = 0;
packet_header.packet_type = PACKET_TYPE_DATA_PACKET;
packet_header.packet_number = GUINT64_TO_LE(niobserver->packet_count);
packet_header.original_packet_number = GUINT64_TO_LE(niobserver->packet_count);
niobserver->packet_count++;
packet_header.nano_seconds_since_2000 = GUINT64_TO_LE(capture_nanoseconds);
if (!wtap_dump_file_write(wdh, &packet_header, sizeof(packet_header), memset(&packet_header, 0x00, sizeof(packet_header));
err)) packet_header.packet_magic = observer_packet_magic;
return FALSE; packet_header.network_speed = 1000000;
packet_header.captured_size = (guint16) phdr->caplen;
packet_header.network_size = (guint16) (phdr->len + 4);
packet_header.offset_to_frame = sizeof(packet_header);
packet_header.offset_to_next_packet = sizeof(packet_header) + phdr->caplen;
packet_header.network_type = private_state->network_type;
packet_header.flags = 0x00;
packet_header.number_of_information_elements = 0;
packet_header.packet_type = PACKET_TYPE_DATA_PACKET;
packet_header.packet_number = private_state->packet_count;
packet_header.original_packet_number = packet_header.packet_number;
packet_header.nano_seconds_since_2000 = seconds_since_2000 * 1000000000 + phdr->ts.nsecs;
if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err)) private_state->packet_count++;
return FALSE;
return TRUE; /* write the packet header */
PACKET_ENTRY_HEADER_TO_LE_IN_PLACE(packet_header);
if (!wtap_dump_file_write(wdh, &packet_header, sizeof(packet_header), err)) {
return FALSE;
}
wdh->bytes_dumped += sizeof(packet_header);
/* write the packet data */
if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err)) {
return FALSE;
}
wdh->bytes_dumped += phdr->caplen;
return TRUE;
} }
static gint observer_to_wtap_encap(int observer_encap)
{
switch(observer_encap) {
case OBSERVER_ETHERNET:
return WTAP_ENCAP_ETHERNET;
case OBSERVER_TOKENRING:
return WTAP_ENCAP_TOKEN_RING;
case OBSERVER_FIBRE_CHANNEL:
return WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS;
case OBSERVER_UNDEFINED:
return WTAP_ENCAP_UNKNOWN;
}
return WTAP_ENCAP_UNKNOWN;
}
static gint wtap_to_observer_encap(int wtap_encap)
{
switch(wtap_encap) {
case WTAP_ENCAP_ETHERNET:
return OBSERVER_ETHERNET;
case WTAP_ENCAP_TOKEN_RING:
return OBSERVER_TOKENRING;
case WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS:
return OBSERVER_FIBRE_CHANNEL;
case WTAP_ENCAP_UNKNOWN:
return OBSERVER_UNDEFINED;
}
return OBSERVER_UNDEFINED;
}

View File

@ -3,7 +3,7 @@
*/ */
/*************************************************************************** /***************************************************************************
NetworkInstruments.h - description network_instruments.h - description
------------------- -------------------
begin : Wed Oct 29 2003 begin : Wed Oct 29 2003
copyright : (C) 2003 by root copyright : (C) 2003 by root
@ -26,25 +26,68 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info);
int network_instruments_dump_can_write_encap(int encap); int network_instruments_dump_can_write_encap(int encap);
gboolean network_instruments_dump_open(wtap_dumper *wdh, int *err); gboolean network_instruments_dump_open(wtap_dumper *wdh, int *err);
/*
* In v15 the high_byte was added to allow a larger offset This was done by
* reducing the size of observer_version by 1 byte. Since version strings are
* only 30 characters the high_byte will always be 0 in previous versions.
*/
typedef struct capture_file_header typedef struct capture_file_header
{ {
char observer_version[32]; char observer_version[31];
guint8 offset_to_first_packet_high_byte; /* allows to extend the offset to the first packet to 256*0x10000 = 16 MB */
guint16 offset_to_first_packet; guint16 offset_to_first_packet;
char probe_instance; char probe_instance;
guint8 number_of_information_elements; /* number of TLVs in the header */ guint8 number_of_information_elements; /* number of TLVs in the header */
} capture_file_header; } capture_file_header;
#define CAPTURE_FILE_HEADER_FROM_LE_IN_PLACE(_capture_file_header) \
_capture_file_header.offset_to_first_packet = GUINT16_FROM_LE((_capture_file_header).offset_to_first_packet)
#define CAPTURE_FILE_HEADER_TO_LE_IN_PLACE(_capture_file_header) \
_capture_file_header.offset_to_first_packet = GUINT16_TO_LE((_capture_file_header).offset_to_first_packet)
typedef struct tlv_header typedef struct tlv_header
{ {
guint16 type; guint16 type;
guint16 length; /* includes the length of the TLV header */ guint16 length; /* includes the length of the TLV header */
} tlv_header; } tlv_header;
#define TLV_HEADER_FROM_LE_IN_PLACE(_tlv_header) \
(_tlv_header).type = GUINT16_FROM_LE((_tlv_header).type); \
(_tlv_header).length = GUINT16_FROM_LE((_tlv_header).length)
#define TLV_HEADER_TO_LE_IN_PLACE(_tlv_header) \
(_tlv_header).type = GUINT16_TO_LE((_tlv_header).type); \
(_tlv_header).length = GUINT16_TO_LE((_tlv_header).length)
typedef struct tlv_time_info {
guint16 type;
guint16 length;
guint32 time_format;
} tlv_time_info;
#define TLV_TIME_INFO_FROM_LE_IN_PLACE(_tlv_time_info) \
(_tlv_time_info).type = GUINT16_FROM_LE((_tlv_time_info).type); \
(_tlv_time_info).length = GUINT16_FROM_LE((_tlv_time_info).length); \
(_tlv_time_info).time_format = GUINT32_FROM_LE((_tlv_time_info).time_format)
#define TLV_TIME_INFO_TO_LE_IN_PLACE(_tlv_time_info) \
(_tlv_time_info).type = GUINT16_TO_LE((_tlv_time_info).type); \
(_tlv_time_info).length = GUINT16_TO_LE((_tlv_time_info).length); \
(_tlv_time_info).time_format = GUINT32_FROM_LE((_tlv_time_info).time_format)
/* /*
* TLV type values. * TLV type values.
*/ */
#define INFORMATION_TYPE_ALIAS_LIST 0x01 #define INFORMATION_TYPE_ALIAS_LIST 0x01
#define INFORMATION_TYPE_COMMENT 0x02 /* ASCII text */ #define INFORMATION_TYPE_COMMENT 0x02 /* ASCII text */
#define INFORMATION_TYPE_TIME_INFO 0x04
/*
* TVL TIME_INFO values.
*/
#define TIME_INFO_LOCAL 0
#define TIME_INFO_GMT 1
typedef struct packet_entry_header typedef struct packet_entry_header
{ {
@ -65,13 +108,39 @@ typedef struct packet_entry_header
guint64 nano_seconds_since_2000; guint64 nano_seconds_since_2000;
} packet_entry_header; } packet_entry_header;
#define PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(_packet_entry_header) \
(_packet_entry_header).packet_magic = GUINT32_FROM_LE((_packet_entry_header).packet_magic); \
(_packet_entry_header).network_speed = GUINT32_FROM_LE((_packet_entry_header).network_speed); \
(_packet_entry_header).captured_size = GUINT16_FROM_LE((_packet_entry_header).captured_size); \
(_packet_entry_header).network_size = GUINT16_FROM_LE((_packet_entry_header).network_size); \
(_packet_entry_header).offset_to_frame = GUINT16_FROM_LE((_packet_entry_header).offset_to_frame); \
(_packet_entry_header).offset_to_next_packet = GUINT16_FROM_LE((_packet_entry_header).offset_to_next_packet); \
(_packet_entry_header).errors = GUINT16_FROM_LE((_packet_entry_header).errors); \
(_packet_entry_header).reserved = GUINT16_FROM_LE((_packet_entry_header).reserved); \
(_packet_entry_header).packet_number = GUINT64_FROM_LE((_packet_entry_header).packet_number); \
(_packet_entry_header).original_packet_number = GUINT64_FROM_LE((_packet_entry_header).original_packet_number); \
(_packet_entry_header).nano_seconds_since_2000 = GUINT64_FROM_LE((_packet_entry_header).nano_seconds_since_2000)
#define PACKET_ENTRY_HEADER_TO_LE_IN_PLACE(_packet_entry_header) \
(_packet_entry_header).packet_magic = GUINT32_TO_LE((_packet_entry_header).packet_magic); \
(_packet_entry_header).network_speed = GUINT32_TO_LE((_packet_entry_header).network_speed); \
(_packet_entry_header).captured_size = GUINT16_TO_LE((_packet_entry_header).captured_size); \
(_packet_entry_header).network_size = GUINT16_TO_LE((_packet_entry_header).network_size); \
(_packet_entry_header).offset_to_frame = GUINT16_TO_LE((_packet_entry_header).offset_to_frame); \
(_packet_entry_header).offset_to_next_packet = GUINT16_TO_LE((_packet_entry_header).offset_to_next_packet); \
(_packet_entry_header).errors = GUINT16_TO_LE((_packet_entry_header).errors); \
(_packet_entry_header).reserved = GUINT16_TO_LE((_packet_entry_header).reserved); \
(_packet_entry_header).packet_number = GUINT64_TO_LE((_packet_entry_header).packet_number); \
(_packet_entry_header).original_packet_number = GUINT64_TO_LE((_packet_entry_header).original_packet_number); \
(_packet_entry_header).nano_seconds_since_2000 = GUINT64_TO_LE((_packet_entry_header).nano_seconds_since_2000)
/* /*
* Network type values. * Network type values.
*/ */
#define OBSERVER_UNDEFINED 0xFF #define OBSERVER_UNDEFINED 0xFF
#define OBSERVER_ETHERNET 0x00 #define OBSERVER_ETHERNET 0x00
#define OBSERVER_TOKENRING 0x01 #define OBSERVER_TOKENRING 0x01
#define OBSERVER_FDDI 0x02 #define OBSERVER_FIBRE_CHANNEL 0x08
/* /*
* Packet type values. * Packet type values.

View File

@ -262,7 +262,7 @@ extern "C" {
#define WTAP_FILE_NGSNIFFER_COMPRESSED 30 #define WTAP_FILE_NGSNIFFER_COMPRESSED 30
#define WTAP_FILE_NETXRAY_1_1 31 #define WTAP_FILE_NETXRAY_1_1 31
#define WTAP_FILE_NETXRAY_2_00x 32 #define WTAP_FILE_NETXRAY_2_00x 32
#define WTAP_FILE_NETWORK_INSTRUMENTS_V9 33 #define WTAP_FILE_NETWORK_INSTRUMENTS 33
#define WTAP_FILE_LANALYZER 34 #define WTAP_FILE_LANALYZER 34
#define WTAP_FILE_PPPDUMP 35 #define WTAP_FILE_PPPDUMP 35
#define WTAP_FILE_RADCOM 36 #define WTAP_FILE_RADCOM 36