* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <errno.h>
#include <string.h>
+#include <wsutil/unicode-utils.h>
#include "wtap-int.h"
#include "file_wrappers.h"
-#include "buffer.h"
#include "atm.h"
#include "pcap-encap.h"
#include "netmon.h"
guint32 userdatalength; /* user data size */
guint32 commentdataoffset; /* comment data offset */
guint32 commentdatalength; /* comment data size */
- guint32 statisticsoffset; /* offset to statistics structure */
- guint32 statisticslength; /* length of statistics structure */
+ guint32 processinfooffset; /* offset to process info structure */
+ guint32 processinfocount; /* number of process info structures */
guint32 networkinfooffset; /* offset to network info structure */
guint32 networkinfolength; /* length of network info structure */
};
guint8 timezone_index; /* index of time zone information */
};
+struct netmonrec_comment {
+ guint32 numFramePerComment; /* Currently, this is always set to 1. Each comment is attached to only one frame. */
+ guint32 frameOffset; /* Offset in the capture file table that indicates the beginning of the frame. Key used to match comment with frame */
+ guint8* title; /* Comment title */
+ guint32 descLength; /* Number of bytes in the comment description. Must be at least zero. */
+ guint8* description; /* Comment description */
+};
+
+/* Just the first few fields of netmonrec_comment so it can be read sequentially from file */
+struct netmonrec_comment_header {
+ guint32 numFramePerComment;
+ guint32 frameOffset;
+ guint32 titleLength;
+};
+
+union ip_address {
+ guint32 ipv4;
+ ws_in6_addr ipv6;
+};
+
+struct netmonrec_process_info {
+ guint8* path; /* A Unicode string of length PathSize */
+ guint32 iconSize;
+ guint8* iconData;
+ guint32 pid;
+ guint16 localPort;
+ guint16 remotePort;
+ gboolean isIPv6;
+ union ip_address localAddr;
+ union ip_address remoteAddr;
+};
+
/*
* The link-layer header on ATM packets.
*/
};
typedef struct {
- time_t start_secs;
- guint32 start_nsecs;
- guint8 version_major;
- guint8 version_minor;
+ time_t start_secs;
+ guint32 start_nsecs;
+ guint8 version_major;
+ guint8 version_minor;
guint32 *frame_table;
- guint32 frame_table_size;
- guint current_frame;
+ guint32 frame_table_size;
+ GHashTable* comment_table;
+ GHashTable* process_info_table;
+ guint current_frame;
} netmon_t;
+/*
+ * Maximum pathname length supported in the process table; the length
+ * is in a 32-bit field, so we impose a limit to prevent attempts to
+ * allocate too much memory.
+ *
+ * See
+ *
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#maxpath
+ *
+ * The NetMon 3.4 "Capture File Format" documentation says "PathSize must be
+ * greater than 0, and less than MAX_PATH (260 characters)", but, as per that
+ * link above, that limit has been raised in more recent systems.
+ *
+ * We pick a limit of 65536, as that should handle a path length of 32767
+ * UTF-16 octet pairs plus a trailing NUL octet pair.
+ */
+#define MATH_PROCINFO_PATH_SIZE 65536
+
/*
* XXX - at least in some NetMon 3.4 VPN captures, the per-packet
* link-layer type is 0, but the packets have Ethernet headers.
#define NETMON_NET_DNS_CACHE 0xFFFE
#define NETMON_NET_NETMON_FILTER 0xFFFF
-static int netmon_read(wtap *wth, int *err, gchar **err_info,
+static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
gint64 *data_offset);
-static int netmon_seek_read(wtap *wth, gint64 seek_off,
- struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
+static gboolean netmon_seek_read(wtap *wth, gint64 seek_off,
+ wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
-static int netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err,
- gchar **err_info);
-static void netmon_sequential_close(wtap *wth);
-static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
- const guint8 *pd, int *err);
-static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
-
-int netmon_open(wtap *wth, int *err, gchar **err_info)
+static void netmon_close(wtap *wth);
+static gboolean netmon_dump(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info);
+static gboolean netmon_dump_finish(wtap_dumper *wdh, int *err);
+
+/*
+ * Convert a counted UTF-16 string, which is probably also null-terminated
+ * but is not guaranteed to be null-terminated (as it came from a file),
+ * to a null-terminated UTF-8 string.
+ */
+static guint8 *
+utf_16_to_utf_8(const guint8 *in, guint32 length)
+{
+ guint8 *result, *out;
+ gunichar2 uchar2;
+ gunichar uchar;
+ size_t n_bytes;
+ guint32 i;
+
+ /*
+ * Get the length of the resulting UTF-8 string, and validate
+ * the input string in the process.
+ */
+ n_bytes = 0;
+ for (i = 0; i + 1 < length && (uchar2 = pletoh16(in + i)) != '\0';
+ i += 2) {
+ if (IS_LEAD_SURROGATE(uchar2)) {
+ /*
+ * Lead surrogate. Must be followed by a trail
+ * surrogate.
+ */
+ gunichar2 lead_surrogate;
+
+ i += 2;
+ if (i + 1 >= length) {
+ /*
+ * Oops, string ends with a lead surrogate.
+ * Ignore this for now.
+ * XXX - insert "substitute" character?
+ * Report the error in some other fashion?
+ */
+ break;
+ }
+ lead_surrogate = uchar2;
+ uchar2 = pletoh16(in + i);
+ if (uchar2 == '\0') {
+ /*
+ * Oops, string ends with a lead surrogate.
+ * Ignore this for now.
+ * XXX - insert "substitute" character?
+ * Report the error in some other fashion?
+ */
+ break;
+ }
+ if (IS_TRAIL_SURROGATE(uchar2)) {
+ /* Trail surrogate. */
+ uchar = SURROGATE_VALUE(lead_surrogate, uchar2);
+ n_bytes += g_unichar_to_utf8(uchar, NULL);
+ } else {
+ /*
+ * Not a trail surrogate.
+ * Ignore the entire pair.
+ * XXX - insert "substitute" character?
+ * Report the error in some other fashion?
+ */
+ ;
+ }
+ } else {
+ if (IS_TRAIL_SURROGATE(uchar2)) {
+ /*
+ * Trail surrogate without a preceding
+ * lead surrogate. Ignore it.
+ * XXX - insert "substitute" character?
+ * Report the error in some other fashion?
+ */
+ ;
+ } else {
+ /*
+ * Non-surrogate; just count it.
+ */
+ n_bytes += g_unichar_to_utf8(uchar2, NULL);
+ }
+ }
+ }
+
+ /*
+ * Now allocate a buffer big enough for the UTF-8 string plus a
+ * trailing NUL, and generate the string.
+ */
+ result = (guint8 *)g_malloc(n_bytes + 1);
+
+ out = result;
+ for (i = 0; i + 1 < length && (uchar2 = pletoh16(in + i)) != '\0';
+ i += 2) {
+ if (IS_LEAD_SURROGATE(uchar2)) {
+ /*
+ * Lead surrogate. Must be followed by a trail
+ * surrogate.
+ */
+ gunichar2 lead_surrogate;
+
+ i += 2;
+ if (i + 1 >= length) {
+ /*
+ * Oops, string ends with a lead surrogate.
+ * Ignore this for now.
+ * XXX - insert "substitute" character?
+ * Report the error in some other fashion?
+ */
+ break;
+ }
+ lead_surrogate = uchar2;
+ uchar2 = pletoh16(in + i);
+ if (uchar2 == '\0') {
+ /*
+ * Oops, string ends with a lead surrogate.
+ * Ignore this for now.
+ * XXX - insert "substitute" character?
+ * Report the error in some other fashion?
+ */
+ break;
+ }
+ if (IS_TRAIL_SURROGATE(uchar2)) {
+ /* Trail surrogate. */
+ uchar = SURROGATE_VALUE(lead_surrogate, uchar2);
+ out += g_unichar_to_utf8(uchar, out);
+ } else {
+ /*
+ * Not a trail surrogate.
+ * Ignore the entire pair.
+ * XXX - insert "substitute" character?
+ * Report the error in some other fashion?
+ */
+ ;
+ }
+ } else {
+ if (IS_TRAIL_SURROGATE(uchar2)) {
+ /*
+ * Trail surrogate without a preceding
+ * lead surrogate. Ignore it.
+ * XXX - insert "substitute" character?
+ * Report the error in some other fashion?
+ */
+ ;
+ } else {
+ /*
+ * Non-surrogate; just count it.
+ */
+ out += g_unichar_to_utf8(uchar2, out);
+ }
+ }
+ }
+ *out = '\0';
+
+ /*
+ * XXX - if i < length, this means we were handed an odd
+ * number of bytes, so it was not a valid UTF-16 string.
+ */
+ return result;
+}
+
+
+static void netmonrec_comment_destroy(gpointer key) {
+ struct netmonrec_comment *comment = (struct netmonrec_comment*) key;
+
+ g_free(comment->title);
+ g_free(comment->description);
+ g_free(comment);
+}
+
+static void netmonrec_process_info_destroy(gpointer key) {
+ struct netmonrec_process_info *process_info = (struct netmonrec_process_info*) key;
+
+ g_free(process_info->path);
+ g_free(process_info->iconData);
+ g_free(process_info);
+}
+
+wtap_open_return_val netmon_open(wtap *wth, int *err, gchar **err_info)
{
- int bytes_read;
char magic[MAGIC_SIZE];
struct netmon_hdr hdr;
int file_type;
guint32 frame_table_length;
guint32 frame_table_size;
guint32 *frame_table;
-#ifdef WORDS_BIGENDIAN
+ guint32 comment_table_offset, process_info_table_offset;
+ guint32 comment_table_size, process_info_table_count;
+ GHashTable *comment_table, *process_info_table;
+ struct netmonrec_comment* comment_rec;
+ gint64 file_size = wtap_file_size(wth, err);
+#if G_BYTE_ORDER == G_BIG_ENDIAN
unsigned int i;
#endif
netmon_t *netmon;
/* Read in the string that should be at the start of a Network
* Monitor file */
- errno = WTAP_ERR_CANT_READ;
- bytes_read = file_read(magic, MAGIC_SIZE, wth->fh);
- if (bytes_read != MAGIC_SIZE) {
- *err = file_error(wth->fh, err_info);
- if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
- return -1;
- return 0;
+ if (!wtap_read_bytes(wth->fh, magic, MAGIC_SIZE, err, err_info)) {
+ if (*err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
}
if (memcmp(magic, netmon_1_x_magic, MAGIC_SIZE) != 0 &&
memcmp(magic, netmon_2_x_magic, MAGIC_SIZE) != 0) {
- return 0;
+ return WTAP_OPEN_NOT_MINE;
}
/* Read the rest of the header. */
- errno = WTAP_ERR_CANT_READ;
- bytes_read = file_read(&hdr, sizeof hdr, wth->fh);
- if (bytes_read != sizeof hdr) {
- *err = file_error(wth->fh, err_info);
- if (*err == 0)
- *err = WTAP_ERR_SHORT_READ;
- return -1;
- }
+ if (!wtap_read_bytes(wth->fh, &hdr, sizeof hdr, err, err_info))
+ return WTAP_OPEN_ERROR;
switch (hdr.ver_major) {
default:
*err = WTAP_ERR_UNSUPPORTED;
*err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
- return -1;
+ return WTAP_OPEN_ERROR;
}
hdr.network = pletoh16(&hdr.network);
if (hdr.network >= NUM_NETMON_ENCAPS
|| netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
- *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err = WTAP_ERR_UNSUPPORTED;
*err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
hdr.network);
- return -1;
+ return WTAP_OPEN_ERROR;
}
/* This is a netmon file */
wth->file_type_subtype = file_type;
- netmon = (netmon_t *)g_malloc(sizeof(netmon_t));
+ netmon = (netmon_t *)g_malloc0(sizeof(netmon_t));
wth->priv = (void *)netmon;
wth->subtype_read = netmon_read;
wth->subtype_seek_read = netmon_seek_read;
- wth->subtype_sequential_close = netmon_sequential_close;
+ wth->subtype_close = netmon_close;
+#if 0
/* NetMon capture file formats v2.1+ use per-packet encapsulation types. NetMon 3 sets the value in
* the header to 1 (Ethernet) for backwards compability. */
if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
wth->file_encap = WTAP_ENCAP_PER_PACKET;
else
- wth->file_encap = netmon_encap[hdr.network];
+#endif
+ wth->file_encap = netmon_encap[hdr.network];
wth->snapshot_length = 0; /* not available in header */
/*
netmon->version_minor = hdr.ver_minor;
/*
- * No frame table allocated yet; initialize these in case we
- * get an error before allocating it or when trying to allocate
- * it, so that the attempt to release the private data on failure
- * doesn't crash.
+ * Get the offset of the frame index table.
*/
- netmon->frame_table_size = 0;
- netmon->frame_table = NULL;
+ frame_table_offset = pletoh32(&hdr.frametableoffset);
/*
- * Get the offset of the frame index table.
+ * For NetMon 2.2 format and later, get the offset and length of
+ * the comment index table and process info table.
+ *
+ * For earlier versions, set them to zero; they appear to be
+ * uninitialized, so they're not necessarily zero.
*/
- frame_table_offset = pletoh32(&hdr.frametableoffset);
+ if ((netmon->version_major == 2 && netmon->version_minor >= 2) ||
+ netmon->version_major > 2) {
+ comment_table_offset = pletoh32(&hdr.commentdataoffset);
+ comment_table_size = pletoh32(&hdr.commentdatalength);
+ process_info_table_offset = pletoh32(&hdr.processinfooffset);
+ process_info_table_count = pletoh32(&hdr.processinfocount);
+ } else {
+ comment_table_offset = 0;
+ comment_table_size = 0;
+ process_info_table_offset = 0;
+ process_info_table_count = 0;
+ }
/*
* It appears that some NetMon 2.x files don't have the
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
frame_table_length);
- return -1;
+ return WTAP_OPEN_ERROR;
}
if (frame_table_size == 0) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
frame_table_length);
- return -1;
+ return WTAP_OPEN_ERROR;
}
/*
* XXX - clamp the size of the frame table, so that we don't
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup_printf("netmon: frame table length is %u, which is larger than we support",
frame_table_length);
- return -1;
+ return WTAP_OPEN_ERROR;
}
if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
- return -1;
+ return WTAP_OPEN_ERROR;
+ }
+
+ /*
+ * Sanity check the comment table information before we bother to allocate
+ * large chunks of memory for the frame table
+ */
+ if (comment_table_size > 0) {
+ /*
+ * XXX - clamp the size of the comment table, so that we don't
+ * attempt to allocate a huge comment table and fail.
+ *
+ * Just use same size requires as frame table
+ */
+ if (comment_table_size > 512*1024*1024) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("netmon: comment table size is %u, which is larger than we support",
+ comment_table_size);
+ return WTAP_OPEN_ERROR;
+ }
+
+ if (comment_table_size < 17) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("netmon: comment table size is %u, which is too small to use",
+ comment_table_size);
+ return WTAP_OPEN_ERROR;
+ }
+
+ if (comment_table_offset > file_size) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("netmon: comment table offset (%u) is larger than file",
+ comment_table_offset);
+ return WTAP_OPEN_ERROR;
+ }
}
+
+ /*
+ * Sanity check the process info table information before we bother to allocate
+ * large chunks of memory for the frame table
+ */
+ if ((process_info_table_offset > 0) && (process_info_table_count > 0)) {
+ /*
+ * XXX - clamp the size of the process info table, so that we don't
+ * attempt to allocate a huge process info table and fail.
+ */
+ if (process_info_table_count > 512*1024) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("netmon: process info table size is %u, which is larger than we support",
+ process_info_table_count);
+ return WTAP_OPEN_ERROR;
+ }
+
+ if (process_info_table_offset > file_size) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("netmon: process info table offset (%u) is larger than file",
+ process_info_table_offset);
+ return WTAP_OPEN_ERROR;
+ }
+ }
+
+ /*
+ * Return back to the frame table offset
+ */
+ if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
+ return WTAP_OPEN_ERROR;
+ }
+
+ /*
+ * Sanity check the process info table information before we bother to allocate
+ * large chunks of memory for the frame table
+ */
+
frame_table = (guint32 *)g_try_malloc(frame_table_length);
if (frame_table_length != 0 && frame_table == NULL) {
*err = ENOMEM; /* we assume we're out of memory */
- return -1;
+ return WTAP_OPEN_ERROR;
}
- errno = WTAP_ERR_CANT_READ;
- bytes_read = file_read(frame_table, frame_table_length, wth->fh);
- if ((guint32)bytes_read != frame_table_length) {
- *err = file_error(wth->fh, err_info);
- if (*err == 0)
- *err = WTAP_ERR_SHORT_READ;
+ if (!wtap_read_bytes(wth->fh, frame_table, frame_table_length,
+ err, err_info)) {
g_free(frame_table);
- return -1;
+ return WTAP_OPEN_ERROR;
}
netmon->frame_table_size = frame_table_size;
netmon->frame_table = frame_table;
-#ifdef WORDS_BIGENDIAN
+ if (comment_table_size > 0) {
+ comment_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, netmonrec_comment_destroy);
+ if (comment_table == NULL) {
+ *err = ENOMEM; /* we assume we're out of memory */
+ return WTAP_OPEN_ERROR;
+ }
+
+ /* Make sure the file contains the full comment section */
+ if (file_seek(wth->fh, comment_table_offset+comment_table_size, SEEK_SET, err) == -1) {
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ if (file_seek(wth->fh, comment_table_offset, SEEK_SET, err) == -1) {
+ /* Shouldn't fail... */
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ while (comment_table_size > 16) {
+ struct netmonrec_comment_header comment_header;
+ guint32 title_length;
+ guint32 desc_length;
+ guint8 *utf16_str;
+
+ /* Read the first 12 bytes of the structure */
+ if (!wtap_read_bytes(wth->fh, &comment_header, 12, err, err_info)) {
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+ comment_table_size -= 12;
+
+ /* Make sure comment size is sane */
+ title_length = pletoh32(&comment_header.titleLength);
+ if (title_length == 0) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("netmon: comment title size can't be 0");
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+ if (title_length > comment_table_size) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("netmon: comment title size is %u, which is larger than the amount remaining in the comment section (%u)",
+ title_length, comment_table_size);
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ comment_rec = g_new0(struct netmonrec_comment, 1);
+ comment_rec->numFramePerComment = pletoh32(&comment_header.numFramePerComment);
+ comment_rec->frameOffset = pletoh32(&comment_header.frameOffset);
+
+ g_hash_table_insert(comment_table, GUINT_TO_POINTER(comment_rec->frameOffset), comment_rec);
+
+ /*
+ * Read in the comment title.
+ *
+ * It is in UTF-16-encoded Unicode, and the title
+ * size is a count of octets, not octet pairs or
+ * Unicode characters.
+ */
+ utf16_str = (guint8*)g_malloc(title_length);
+ if (!wtap_read_bytes(wth->fh, utf16_str, title_length,
+ err, err_info)) {
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+ comment_table_size -= title_length;
+
+ /*
+ * Now convert it to UTF-8 for internal use.
+ */
+ comment_rec->title = utf_16_to_utf_8(utf16_str,
+ title_length);
+ g_free(utf16_str);
+
+ if (comment_table_size < 4) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("netmon: corrupt comment section");
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ if (!wtap_read_bytes(wth->fh, &desc_length, 4, err, err_info)) {
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+ comment_table_size -= 4;
+
+ comment_rec->descLength = pletoh32(&desc_length);
+ if (comment_rec->descLength > 0) {
+ /* Make sure comment size is sane */
+ if (comment_rec->descLength > comment_table_size) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("netmon: comment description size is %u, which is larger than the amount remaining in the comment section (%u)",
+ comment_rec->descLength, comment_table_size);
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ comment_rec->description = (guint8*)g_malloc(comment_rec->descLength);
+
+ /* Read the comment description */
+ if (!wtap_read_bytes(wth->fh, comment_rec->description, comment_rec->descLength, err, err_info)) {
+ g_hash_table_destroy(comment_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ comment_table_size -= comment_rec->descLength;
+ }
+ }
+ netmon->comment_table = comment_table;
+ }
+
+ if ((process_info_table_offset > 0) && (process_info_table_count > 0)) {
+ guint16 version;
+
+ /* Go to the process table offset */
+ if (file_seek(wth->fh, process_info_table_offset, SEEK_SET, err) == -1) {
+ return WTAP_OPEN_ERROR;
+ }
+
+ process_info_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, netmonrec_process_info_destroy);
+ if (process_info_table == NULL) {
+ *err = ENOMEM; /* we assume we're out of memory */
+ return WTAP_OPEN_ERROR;
+ }
+
+ /* Read the version (ignored for now) */
+ if (!wtap_read_bytes(wth->fh, &version, 2, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ while (process_info_table_count > 0)
+ {
+ struct netmonrec_process_info* process_info;
+ guint32 tmp32;
+ guint16 tmp16;
+ guint32 path_size;
+ guint8 *utf16_str;
+
+ process_info = g_new0(struct netmonrec_process_info, 1);
+
+ /* Read path */
+ if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
+ g_free(process_info);
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ path_size = pletoh32(&tmp32);
+ if (path_size > MATH_PROCINFO_PATH_SIZE) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("netmon: Path size for process info record is %u, which is larger than allowed max value (%u)",
+ path_size, MATH_PROCINFO_PATH_SIZE);
+ g_free(process_info);
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ /*
+ * Read in the path string.
+ *
+ * It is in UTF-16-encoded Unicode, and the path
+ * size is a count of octets, not octet pairs or
+ * Unicode characters.
+ */
+ utf16_str = (guint8*)g_malloc(path_size);
+ if (!wtap_read_bytes(wth->fh, utf16_str, path_size,
+ err, err_info)) {
+ g_free(process_info);
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ /*
+ * Now convert it to UTF-8 for internal use.
+ */
+ process_info->path = utf_16_to_utf_8(utf16_str,
+ path_size);
+ g_free(utf16_str);
+
+ /* Read icon (currently not saved) */
+ if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
+ g_free(process_info);
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ process_info->iconSize = pletoh32(&tmp32);
+
+ /* XXX - skip the icon for now */
+ if (file_seek(wth->fh, process_info->iconSize, SEEK_CUR, err) == -1) {
+ g_free(process_info);
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ process_info->iconSize = 0;
+
+ if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
+ g_free(process_info);
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ process_info->pid = pletoh32(&tmp32);
+
+ /* XXX - Currently index process information by PID */
+ g_hash_table_insert(process_info_table, GUINT_TO_POINTER(process_info->pid), process_info);
+
+ /* Read local port */
+ if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ process_info->localPort = pletoh16(&tmp16);
+
+ /* Skip padding */
+ if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ /* Read remote port */
+ if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ process_info->remotePort = pletoh16(&tmp16);
+
+ /* Skip padding */
+ if (!wtap_read_bytes(wth->fh, &tmp16, 2, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+
+ /* Determine IP version */
+ if (!wtap_read_bytes(wth->fh, &tmp32, 4, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ process_info->isIPv6 = ((pletoh32(&tmp32) == 0) ? FALSE : TRUE);
+
+ if (process_info->isIPv6) {
+ if (!wtap_read_bytes(wth->fh, &process_info->localAddr.ipv6, 16, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ if (!wtap_read_bytes(wth->fh, &process_info->remoteAddr.ipv6, 16, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ } else {
+ guint8 ipbuffer[16];
+ if (!wtap_read_bytes(wth->fh, ipbuffer, 16, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ process_info->localAddr.ipv4 = pletoh32(ipbuffer);
+
+ if (!wtap_read_bytes(wth->fh, ipbuffer, 16, err, err_info)) {
+ g_hash_table_destroy(process_info_table);
+ return WTAP_OPEN_ERROR;
+ }
+ process_info->remoteAddr.ipv4 = pletoh32(ipbuffer);
+ }
+
+ process_info_table_count--;
+ }
+
+ netmon->process_info_table = process_info_table;
+ }
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
/*
* OK, now byte-swap the frame table.
*/
* Version 1.x of the file format supports
* millisecond precision.
*/
- wth->tsprecision = WTAP_FILE_TSPREC_MSEC;
+ wth->file_tsprec = WTAP_TSPREC_MSEC;
break;
case 2:
* currently support that, so say
* "nanosecond precision" for now.
*/
- wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
+ wth->file_tsprec = WTAP_TSPREC_NSEC;
break;
}
- return 1;
-}
-
-static size_t
-netmon_trailer_size(netmon_t *netmon)
-{
- if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
- netmon->version_major > 2) {
- if (netmon->version_major > 2) {
- /*
- * Asssume 2.3 format, for now.
- */
- return sizeof (struct netmonrec_2_3_trlr);
- } else {
- switch (netmon->version_minor) {
-
- case 1:
- return sizeof (struct netmonrec_2_1_trlr);
-
- case 2:
- return sizeof (struct netmonrec_2_2_trlr);
-
- default:
- return sizeof (struct netmonrec_2_3_trlr);
- }
- }
- }
- return 0; /* no trailer */
+ return WTAP_OPEN_MINE;
}
static void
-netmon_set_pseudo_header_info(int pkt_encap, struct wtap_pkthdr *phdr,
- Buffer *buf)
+netmon_set_pseudo_header_info(wtap_rec *rec, Buffer *buf)
{
- guint8 *pd = buffer_start_ptr(buf);
-
- switch (pkt_encap) {
+ switch (rec->rec_header.packet_header.pkt_encap) {
case WTAP_ENCAP_ATM_PDUS:
/*
* Attempt to guess from the packet data, the VPI, and
* the VCI information about the type of traffic.
*/
- atm_guess_traffic_type(phdr, pd);
+ atm_guess_traffic_type(rec, ws_buffer_start_ptr(buf));
break;
case WTAP_ENCAP_ETHERNET:
/*
* We assume there's no FCS in this frame.
*/
- phdr->pseudo_header.eth.fcs_len = 0;
+ rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
break;
case WTAP_ENCAP_IEEE_802_11_NETMON:
/*
* It appears to be the case that management
- * frames have an FCS and data frames don't;
- * I'm not sure about control frames. An
- * "FCS length" of -2 means "NetMon weirdness".
+ * frames (and control and extension frames ?) may
+ * or may not have an FCS and data frames don't.
+ * (Netmon capture files have been seen for this
+ * encapsulation having management frames either
+ * completely with or without an FCS. Also: instances have been
+ * seen where both Management and Control frames
+ * do not have an FCS).
+ * An "FCS length" of -2 means "NetMon weirdness".
*/
- phdr->pseudo_header.ieee_802_11.fcs_len = -2;
- phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
+ memset(&rec->rec_header.packet_header.pseudo_header.ieee_802_11, 0, sizeof(rec->rec_header.packet_header.pseudo_header.ieee_802_11));
+ rec->rec_header.packet_header.pseudo_header.ieee_802_11.fcs_len = -2;
+ rec->rec_header.packet_header.pseudo_header.ieee_802_11.decrypted = FALSE;
+ rec->rec_header.packet_header.pseudo_header.ieee_802_11.datapad = FALSE;
+ rec->rec_header.packet_header.pseudo_header.ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
break;
}
}
-static gboolean netmon_process_rec_header(wtap *wth, FILE_T fh,
- struct wtap_pkthdr *phdr, int *err, gchar **err_info)
+typedef enum {
+ SUCCESS,
+ FAILURE,
+ RETRY
+} process_record_retval;
+
+static process_record_retval
+netmon_process_record(wtap *wth, FILE_T fh, wtap_rec *rec,
+ Buffer *buf, int *err, gchar **err_info)
{
netmon_t *netmon = (netmon_t *)wth->priv;
int hdr_size = 0;
struct netmonrec_1_x_hdr hdr_1_x;
struct netmonrec_2_x_hdr hdr_2_x;
} hdr;
- int bytes_read;
gint64 delta = 0; /* signed - frame times can be before the nominal start */
gint64 t;
time_t secs;
- guint32 nsecs;
+ int nsecs;
guint32 packet_size = 0;
guint32 orig_size = 0;
+ int trlr_size;
+ union {
+ struct netmonrec_2_1_trlr trlr_2_1;
+ struct netmonrec_2_2_trlr trlr_2_2;
+ struct netmonrec_2_3_trlr trlr_2_3;
+ } trlr;
+ guint16 network;
+ int pkt_encap;
+ struct netmonrec_comment* comment_rec = NULL;
/* Read record header. */
switch (netmon->version_major) {
hdr_size = sizeof (struct netmonrec_2_x_hdr);
break;
}
- errno = WTAP_ERR_CANT_READ;
-
- bytes_read = file_read(&hdr, hdr_size, fh);
- if (bytes_read != hdr_size) {
- *err = file_error(fh, err_info);
- if (*err == 0 && bytes_read != 0) {
- *err = WTAP_ERR_SHORT_READ;
- }
- return FALSE;
- }
+ if (!wtap_read_bytes_or_eof(fh, &hdr, hdr_size, err, err_info))
+ return FAILURE;
switch (netmon->version_major) {
packet_size = pletoh32(&hdr.hdr_2_x.incl_len);
break;
}
- if (packet_size > WTAP_MAX_PACKET_SIZE) {
+ if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
/*
* Probably a corrupt capture file; don't blow up trying
* to allocate space for an immensely-large packet.
*/
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
- packet_size, WTAP_MAX_PACKET_SIZE);
- return FALSE;
+ packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
+ return FAILURE;
}
+ rec->rec_type = REC_TYPE_PACKET;
+
/*
* If this is an ATM packet, the first
* "sizeof (struct netmon_atm_hdr)" bytes have destination and
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
packet_size);
- return FALSE;
+ return FAILURE;
}
- if (!netmon_read_atm_pseudoheader(fh, &phdr->pseudo_header,
+ if (!netmon_read_atm_pseudoheader(fh, &rec->rec_header.packet_header.pseudo_header,
err, err_info))
- return FALSE; /* Read error */
+ return FAILURE; /* Read error */
/*
* Don't count the pseudo-header as part of the packet.
secs--;
}
secs += (time_t)(t/1000000000);
- nsecs = (guint32)(t%1000000000);
- phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
- phdr->ts.secs = netmon->start_secs + secs;
- phdr->ts.nsecs = nsecs;
- phdr->caplen = packet_size;
- phdr->len = orig_size;
+ nsecs = (int)(t%1000000000);
+ rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
+ rec->ts.secs = netmon->start_secs + secs;
+ rec->ts.nsecs = nsecs;
+ rec->rec_header.packet_header.caplen = packet_size;
+ rec->rec_header.packet_header.len = orig_size;
- return TRUE;
-}
+ /*
+ * Read the packet data.
+ */
+ if (!wtap_read_packet_bytes(fh, buf, rec->rec_header.packet_header.caplen, err, err_info))
+ return FAILURE;
-typedef enum {
- SUCCESS,
- FAILURE,
- RETRY
-} process_trailer_retval;
+ /*
+ * For version 2.1 and later, there's additional information
+ * after the frame data.
+ */
+ if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
+ netmon->version_major > 2) {
+ if (netmon->version_major > 2) {
+ /*
+ * Asssume 2.3 format, for now.
+ */
+ trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
+ } else {
+ switch (netmon->version_minor) {
-static process_trailer_retval netmon_process_rec_trailer(netmon_t *netmon,
- FILE_T fh, struct wtap_pkthdr *phdr, int *err, gchar **err_info)
-{
- int trlr_size;
+ case 1:
+ trlr_size = (int)sizeof (struct netmonrec_2_1_trlr);
+ break;
- trlr_size = (int)netmon_trailer_size(netmon);
- if (trlr_size != 0) {
- /*
- * I haz a trailer.
+ case 2:
+ trlr_size = (int)sizeof (struct netmonrec_2_2_trlr);
+ break;
+
+ default:
+ trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
+ break;
+ }
+ }
+
+ if (!wtap_read_bytes(fh, &trlr, trlr_size, err, err_info))
+ return FAILURE;
+
+ network = pletoh16(trlr.trlr_2_1.network);
+ if ((network >= 0xE080) && (network <= 0xE08A)) {
+ /* These values "violate" the LINKTYPE_ media type values
+ * in Microsoft Analyzer and are considered a MAExportedMediaType,
+ * so they need their own WTAP_ types
+ */
+ switch (network)
+ {
+ case 0xE080: // "WiFi Message"
+ pkt_encap = WTAP_ENCAP_IEEE_802_11;
+ break;
+ case 0xE081: // "Ndis Etw WiFi Channel Message"
+ case 0xE082: // "Fiddler Netmon Message"
+ case 0xE089: // "Pef Ndis Msg";
+ case 0xE08A: // "Pef Ndis Wifi Meta Msg";
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported", network);
+ return FAILURE;
+ case 0xE083:
+ pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_V4;
+ break;
+ case 0xE084:
+ pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_V6;
+ break;
+ case 0xE085:
+ pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_2V4;
+ break;
+ case 0xE086:
+ pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_2V6;
+ break;
+ case 0xE087:
+ pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_AUTH_V4;
+ break;
+ case 0xE088:
+ pkt_encap = WTAP_ENCAP_MA_WFP_CAPTURE_AUTH_V6;
+ break;
+ default:
+ pkt_encap = WTAP_ENCAP_UNKNOWN;
+ break;
+ }
+ } else if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
+ /*
+ * Converted pcap file - the LINKTYPE_ value
+ * is the network value with 0xF000 masked off.
+ */
+ network &= 0x0FFF;
+ pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
+ if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
+ network);
+ return FAILURE;
+ }
+ } else if (network < NUM_NETMON_ENCAPS) {
+ /*
+ * Regular NetMon encapsulation.
+ */
+ pkt_encap = netmon_encap[network];
+ if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
+ network);
+ return FAILURE;
+ }
+ } else {
+ /*
+ * Special packet type for metadata.
+ */
+ switch (network) {
+
+ case NETMON_NET_NETEVENT:
+ /*
+ * Event Tracing event.
+ *
+ * http://msdn.microsoft.com/en-us/library/aa363759(VS.85).aspx
+ */
+ pkt_encap = WTAP_ENCAP_NETMON_NET_NETEVENT;
+ break;
+
+ case NETMON_NET_NETWORK_INFO_EX:
+ /*
+ * List of adapters on which the capture
+ * was done.
+ * XXX - this could be translated into pcapng
+ * blocks but for now, just treat as a frame.
+ */
+ pkt_encap = WTAP_ENCAP_NETMON_NETWORK_INFO_EX;
+ break;
+
+ case NETMON_NET_PAYLOAD_HEADER:
+ /*
+ * Header for a fake frame constructed
+ * by reassembly.
+ */
+ return RETRY;
+
+ case NETMON_NET_NETWORK_INFO:
+ /*
+ * List of adapters on which the capture
+ * was done.
+ */
+ return RETRY;
+
+ case NETMON_NET_DNS_CACHE:
+ /*
+ * List of resolved IP addresses.
+ */
+ return RETRY;
+
+ case NETMON_NET_NETMON_FILTER:
+ /*
+ * NetMon capture or display filter
+ * string.
+ */
+ pkt_encap = WTAP_ENCAP_NETMON_NET_FILTER;
+ break;
+
+ default:
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
+ network);
+ return FAILURE;
+ }
+ }
+
+ rec->rec_header.packet_header.pkt_encap = pkt_encap;
+ if (netmon->version_major > 2 || netmon->version_minor > 2) {
+ guint64 d;
+
+ d = pletoh64(trlr.trlr_2_3.utc_timestamp);
+
+ /*
+ * Get the time as seconds and nanoseconds.
+ * and overwrite the time stamp obtained
+ * from the record header.
+ */
+ if (!filetime_to_nstime(&rec->ts, d)) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("netmon: time stamp outside supported range");
+ return FAILURE;
+ }
+ }
+ }
+
+ netmon_set_pseudo_header_info(rec, buf);
+
+ /* If any header specific information is present, set it as pseudo header data
+ * and set the encapsulation type, so it can be handled to the netmon_header
+ * dissector for further processing
+ */
+ if (netmon->comment_table != NULL) {
+ comment_rec = (struct netmonrec_comment*)g_hash_table_lookup(netmon->comment_table, GUINT_TO_POINTER(netmon->frame_table[netmon->current_frame-1]));
+ }
+
+ if (comment_rec != NULL) {
+ union wtap_pseudo_header temp_header;
+
+ /* These are the current encapsulation types that NetMon uses.
+ * Save them off so they can be copied to the NetMon pseudoheader
*/
- phdr->pkt_encap = netmon_read_rec_trailer(fh,
- trlr_size, err, err_info);
- if (phdr->pkt_encap == -1)
- return FAILURE; /* error */
- if (phdr->pkt_encap == 0)
- return RETRY;
+ switch (rec->rec_header.packet_header.pkt_encap)
+ {
+ case WTAP_ENCAP_ATM_PDUS:
+ memcpy(&temp_header.atm, &rec->rec_header.packet_header.pseudo_header.atm, sizeof(temp_header.atm));
+ break;
+ case WTAP_ENCAP_ETHERNET:
+ memcpy(&temp_header.eth, &rec->rec_header.packet_header.pseudo_header.eth, sizeof(temp_header.eth));
+ break;
+ case WTAP_ENCAP_IEEE_802_11_NETMON:
+ memcpy(&temp_header.ieee_802_11, &rec->rec_header.packet_header.pseudo_header.ieee_802_11, sizeof(temp_header.ieee_802_11));
+ break;
+ }
+ memset(&rec->rec_header.packet_header.pseudo_header.netmon, 0, sizeof(rec->rec_header.packet_header.pseudo_header.netmon));
+
+ /* Save the current encapsulation type to the NetMon pseudoheader */
+ rec->rec_header.packet_header.pseudo_header.netmon.sub_encap = rec->rec_header.packet_header.pkt_encap;
+
+ /* Copy the comment data */
+ rec->rec_header.packet_header.pseudo_header.netmon.title = comment_rec->title;
+ rec->rec_header.packet_header.pseudo_header.netmon.descLength = comment_rec->descLength;
+ rec->rec_header.packet_header.pseudo_header.netmon.description = comment_rec->description;
+
+ /* Copy the saved pseudoheaders to the netmon pseudoheader structure */
+ switch (rec->rec_header.packet_header.pkt_encap)
+ {
+ case WTAP_ENCAP_ATM_PDUS:
+ memcpy(&rec->rec_header.packet_header.pseudo_header.netmon.subheader.atm, &temp_header.atm, sizeof(temp_header.atm));
+ break;
+ case WTAP_ENCAP_ETHERNET:
+ memcpy(&rec->rec_header.packet_header.pseudo_header.netmon.subheader.eth, &temp_header.eth, sizeof(temp_header.eth));
+ break;
+ case WTAP_ENCAP_IEEE_802_11_NETMON:
+ memcpy(&rec->rec_header.packet_header.pseudo_header.netmon.subheader.ieee_802_11, &temp_header.ieee_802_11, sizeof(temp_header.ieee_802_11));
+ break;
+ }
+
+ /* Encapsulation type is now something that can be passed to netmon_header dissector */
+ rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_NETMON_HEADER;
}
return SUCCESS;
}
/* Read the next packet */
-static int netmon_read(wtap *wth, int *err, gchar **err_info,
+static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
gint64 *data_offset)
{
netmon_t *netmon = (netmon_t *)wth->priv;
gint64 rec_offset;
-again:
- /* Have we reached the end of the packet data? */
- if (netmon->current_frame >= netmon->frame_table_size) {
- /* Yes. We won't need the frame table any more;
- free it. */
- g_free(netmon->frame_table);
- netmon->frame_table = NULL;
- *err = 0; /* it's just an EOF, not an error */
- return -1;
- }
+ for (;;) {
+ /* Have we reached the end of the packet data? */
+ if (netmon->current_frame >= netmon->frame_table_size) {
+ *err = 0; /* it's just an EOF, not an error */
+ return FALSE;
+ }
- /* Seek to the beginning of the current record, if we're
- not there already (seeking to the current position
- may still cause a seek and a read of the underlying file,
- so we don't want to do it unconditionally).
-
- Yes, the current record could be before the previous
- record. At least some captures put the trailer record
- with statistics as the first physical record in the
- file, but set the frame table up so it's the last
- record in sequence. */
- rec_offset = netmon->frame_table[netmon->current_frame];
- if (file_tell(wth->fh) != rec_offset) {
- if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
- return -1;
- }
- netmon->current_frame++;
+ /* Seek to the beginning of the current record, if we're
+ not there already (seeking to the current position
+ may still cause a seek and a read of the underlying file,
+ so we don't want to do it unconditionally).
+
+ Yes, the current record could be before the previous
+ record. At least some captures put the trailer record
+ with statistics as the first physical record in the
+ file, but set the frame table up so it's the last
+ record in sequence. */
+ rec_offset = netmon->frame_table[netmon->current_frame];
+ if (file_tell(wth->fh) != rec_offset) {
+ if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
+ return FALSE;
+ }
+ netmon->current_frame++;
- *data_offset = file_tell(wth->fh);
+ *data_offset = file_tell(wth->fh);
- if (!netmon_process_rec_header(wth, wth->fh, &wth->phdr,
- err, err_info))
- return -1;
+ switch (netmon_process_record(wth, wth->fh, &wth->rec,
+ wth->rec_data, err, err_info)) {
- if (!wtap_read_packet_bytes(wth->fh, wth->frame_buffer,
- wth->phdr.caplen, err, err_info))
- return -1; /* Read error */
+ case RETRY:
+ continue;
- /*
- * For version 2.1 and later, there's additional information
- * after the frame data.
- */
- switch (netmon_process_rec_trailer(netmon, wth->fh, &wth->phdr,
- err, err_info)) {
+ case SUCCESS:
+ return TRUE;
- case RETRY:
- goto again;
-
- case SUCCESS:
- break;
-
- case FAILURE:
- return -1;
+ case FAILURE:
+ return FALSE;
+ }
}
-
- netmon_set_pseudo_header_info(wth->phdr.pkt_encap, &wth->phdr,
- wth->frame_buffer);
- return REC_TYPE_PACKET;
}
-static int
+static gboolean
netmon_seek_read(wtap *wth, gint64 seek_off,
- struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
+ wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
{
- netmon_t *netmon = (netmon_t *)wth->priv;
-
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
- return -1;
-
- if (!netmon_process_rec_header(wth, wth->random_fh, phdr,
- err, err_info))
- return -1;
-
- /*
- * Read the packet data.
- */
- if (!wtap_read_packet_bytes(wth->random_fh, buf, phdr->caplen, err,
- err_info))
- return -1;
+ return FALSE;
- /*
- * For version 2.1 and later, there's additional information
- * after the frame data.
- */
- switch (netmon_process_rec_trailer(netmon, wth->random_fh, phdr,
- err, err_info)) {
+ switch (netmon_process_record(wth, wth->random_fh, rec, buf, err,
+ err_info)) {
- case RETRY:
+ default:
/*
* This should not happen.
*/
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
- return -1;
+ return FALSE;
case SUCCESS:
- break;
+ return TRUE;
case FAILURE:
- return -1;
+ return FALSE;
}
-
- netmon_set_pseudo_header_info(phdr->pkt_encap, phdr, buf);
-
- return REC_TYPE_PACKET;
}
static gboolean
int *err, gchar **err_info)
{
struct netmon_atm_hdr atm_phdr;
- int bytes_read;
guint16 vpi, vci;
- errno = WTAP_ERR_CANT_READ;
- bytes_read = file_read(&atm_phdr, sizeof (struct netmon_atm_hdr), fh);
- if (bytes_read != sizeof (struct netmon_atm_hdr)) {
- *err = file_error(fh, err_info);
- if (*err == 0)
- *err = WTAP_ERR_SHORT_READ;
+ if (!wtap_read_bytes(fh, &atm_phdr, sizeof (struct netmon_atm_hdr),
+ err, err_info))
return FALSE;
- }
vpi = g_ntohs(atm_phdr.vpi);
vci = g_ntohs(atm_phdr.vci);
return TRUE;
}
-/*
- * Read a record trailer.
- * On success, returns the packet encapsulation type.
- * On error, returns -1 (which is WTAP_ENCAP_PER_PACKET, but we'd
- * never return that on success).
- * For metadata packets, returns 0 (which is WTAP_ENCAP_UNKNOWN, but
- * we'd never return that on success).
- */
-static int
-netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err, gchar **err_info)
-{
- int bytes_read;
- union {
- struct netmonrec_2_1_trlr trlr_2_1;
- struct netmonrec_2_2_trlr trlr_2_2;
- struct netmonrec_2_3_trlr trlr_2_3;
- } trlr;
- guint16 network;
- int pkt_encap;
-
- errno = WTAP_ERR_CANT_READ;
- bytes_read = file_read(&trlr, trlr_size, fh);
- if (bytes_read != trlr_size) {
- *err = file_error(fh, err_info);
- if (*err == 0 && bytes_read != 0) {
- *err = WTAP_ERR_SHORT_READ;
- }
- return -1; /* error */
- }
-
- network = pletoh16(trlr.trlr_2_1.network);
- if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
- /*
- * Converted pcap file - the LINKTYPE_ value
- * is the network value with 0xF000 masked off.
- */
- network &= 0x0FFF;
- pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
- if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
- *err = WTAP_ERR_UNSUPPORTED_ENCAP;
- *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
- network);
- return -1; /* error */
- }
- } else if (network < NUM_NETMON_ENCAPS) {
- /*
- * Regular NetMon encapsulation.
- */
- pkt_encap = netmon_encap[network];
- if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
- *err = WTAP_ERR_UNSUPPORTED_ENCAP;
- *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
- network);
- return -1; /* error */
- }
- } else {
- /*
- * Special packet type for metadata.
- */
- switch (network) {
-
- case NETMON_NET_NETEVENT:
- case NETMON_NET_NETWORK_INFO_EX:
- case NETMON_NET_PAYLOAD_HEADER:
- case NETMON_NET_NETWORK_INFO:
- case NETMON_NET_DNS_CACHE:
- case NETMON_NET_NETMON_FILTER:
- /*
- * Just ignore those record types, for
- * now. Tell our caller to read the next
- * record.
- */
- return 0;
-
- default:
- *err = WTAP_ERR_UNSUPPORTED_ENCAP;
- *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
- network);
- return -1; /* error */
- }
- }
-
- return pkt_encap; /* success */
-}
-
/* Throw away the frame table used by the sequential I/O stream. */
static void
-netmon_sequential_close(wtap *wth)
+netmon_close(wtap *wth)
{
netmon_t *netmon = (netmon_t *)wth->priv;
g_free(netmon->frame_table);
netmon->frame_table = NULL;
}
+
+ if (netmon->comment_table != NULL) {
+ g_hash_table_destroy(netmon->comment_table);
+ netmon->comment_table = NULL;
+ }
+
+ if (netmon->process_info_table != NULL) {
+ g_hash_table_destroy(netmon->process_info_table);
+ netmon->process_info_table = NULL;
+ }
}
typedef struct {
* format.
*/
if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
- return WTAP_ERR_UNSUPPORTED_ENCAP;
+ return WTAP_ERR_UNWRITABLE_ENCAP;
return 0;
}
return 0;
if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
- return WTAP_ERR_UNSUPPORTED_ENCAP;
+ return WTAP_ERR_UNWRITABLE_ENCAP;
return 0;
}
return FALSE;
wdh->subtype_write = netmon_dump;
- wdh->subtype_close = netmon_dump_close;
+ wdh->subtype_finish = netmon_dump_finish;
netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
wdh->priv = (void *)netmon;
/* Write a record for a packet to a dump file.
Returns TRUE on success, FALSE on failure. */
-static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
- const guint8 *pd, int *err)
+static gboolean netmon_dump(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info _U_)
{
- const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
+ const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
struct netmonrec_1_x_hdr rec_1_x_hdr;
struct netmonrec_2_x_hdr rec_2_x_hdr;
gint64 secs;
gint32 nsecs;
+ /* We can only write packet records. */
+ if (rec->rec_type != REC_TYPE_PACKET) {
+ *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
+ return FALSE;
+ }
+
switch (wdh->file_type_subtype) {
case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
* The length fields are 16-bit, so there's a hard limit
* of 65535.
*/
- if (phdr->caplen > 65535) {
+ if (rec->rec_header.packet_header.caplen > 65535) {
*err = WTAP_ERR_PACKET_TOO_LARGE;
return FALSE;
}
case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
/* Don't write anything we're not willing to read. */
- if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
+ if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
*err = WTAP_ERR_PACKET_TOO_LARGE;
return FALSE;
}
default:
/* We should never get here - our open routine
should only get called for the types above. */
- *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
+ *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
return FALSE;
}
/*
* Is this network type supported?
*/
- if (phdr->pkt_encap < 0 ||
- (unsigned) phdr->pkt_encap >= NUM_WTAP_ENCAPS ||
- wtap_encap[phdr->pkt_encap] == -1) {
+ if (rec->rec_header.packet_header.pkt_encap < 0 ||
+ (unsigned) rec->rec_header.packet_header.pkt_encap >= NUM_WTAP_ENCAPS ||
+ wtap_encap[rec->rec_header.packet_header.pkt_encap] == -1) {
/*
* No. Fail.
*/
- *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err = WTAP_ERR_UNWRITABLE_ENCAP;
return FALSE;
}
/*
* Fill in the trailer with the network type.
*/
- phtoles(rec_2_x_trlr.network, wtap_encap[phdr->pkt_encap]);
+ phtoles(rec_2_x_trlr.network, wtap_encap[rec->rec_header.packet_header.pkt_encap]);
}
/*
* sub-millisecond part of the time stamp off.
*/
if (!netmon->got_first_record_time) {
- netmon->first_record_time.secs = phdr->ts.secs;
+ netmon->first_record_time.secs = rec->ts.secs;
netmon->first_record_time.nsecs =
- (phdr->ts.nsecs/1000000)*1000000;
+ (rec->ts.nsecs/1000000)*1000000;
netmon->got_first_record_time = TRUE;
}
atm_hdrsize = sizeof (struct netmon_atm_hdr);
else
atm_hdrsize = 0;
- secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
- nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
+ secs = (gint64)(rec->ts.secs - netmon->first_record_time.secs);
+ nsecs = rec->ts.nsecs - netmon->first_record_time.nsecs;
while (nsecs < 0) {
/*
* Propagate a borrow into the seconds.
case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
rec_1_x_hdr.ts_delta = GUINT32_TO_LE(secs*1000 + (nsecs + 500000)/1000000);
- rec_1_x_hdr.orig_len = GUINT16_TO_LE(phdr->len + atm_hdrsize);
- rec_1_x_hdr.incl_len = GUINT16_TO_LE(phdr->caplen + atm_hdrsize);
+ rec_1_x_hdr.orig_len = GUINT16_TO_LE(rec->rec_header.packet_header.len + atm_hdrsize);
+ rec_1_x_hdr.incl_len = GUINT16_TO_LE(rec->rec_header.packet_header.caplen + atm_hdrsize);
hdrp = &rec_1_x_hdr;
hdr_size = sizeof rec_1_x_hdr;
break;
case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
rec_2_x_hdr.ts_delta = GUINT64_TO_LE(secs*1000000 + (nsecs + 500)/1000);
- rec_2_x_hdr.orig_len = GUINT32_TO_LE(phdr->len + atm_hdrsize);
- rec_2_x_hdr.incl_len = GUINT32_TO_LE(phdr->caplen + atm_hdrsize);
+ rec_2_x_hdr.orig_len = GUINT32_TO_LE(rec->rec_header.packet_header.len + atm_hdrsize);
+ rec_2_x_hdr.incl_len = GUINT32_TO_LE(rec->rec_header.packet_header.caplen + atm_hdrsize);
hdrp = &rec_2_x_hdr;
hdr_size = sizeof rec_2_x_hdr;
break;
default:
/* We should never get here - our open routine
should only get called for the types above. */
- *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
+ *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
return FALSE;
}
rec_size += sizeof atm_hdr;
}
- if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
+ if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
return FALSE;
- rec_size += phdr->caplen;
+ rec_size += rec->rec_header.packet_header.caplen;
if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
/*
/* Finish writing to a dump file.
Returns TRUE on success, FALSE on failure. */
-static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
+static gboolean netmon_dump_finish(wtap_dumper *wdh, int *err)
{
netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
size_t n_to_write;
/* We should never get here - our open routine
should only get called for the types above. */
if (err != NULL)
- *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
+ *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
return FALSE;
}
if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
return TRUE;
}
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */