aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--wiretap/netmon.c154
1 files changed, 135 insertions, 19 deletions
diff --git a/wiretap/netmon.c b/wiretap/netmon.c
index d255b16bac..082731794e 100644
--- a/wiretap/netmon.c
+++ b/wiretap/netmon.c
@@ -95,6 +95,30 @@ struct netmonrec_2_x_hdr {
};
/*
+ * Network Monitor 2.1 and later record trailers; documented in the Network
+ * Monitor 3.x help files, for 3.3 and later, although they don't clearly
+ * state how the trailer format changes from version to version.
+ *
+ * Some fields are multi-byte integers, but they're not aligned on their
+ * natural boundaries.
+ */
+struct netmonrec_2_1_trlr {
+ guint8 network[2]; /* network type for this packet */
+};
+
+struct netmonrec_2_2_trlr {
+ guint8 network[2]; /* network type for this packet */
+ guint8 process_info_index[4]; /* index into the process info table */
+};
+
+struct netmonrec_2_3_trlr {
+ guint8 network[2]; /* network type for this packet */
+ guint8 process_info_index[4]; /* index into the process info table */
+ guint8 utc_timestamp[8]; /* packet time stamp, as .1 us units since January 1, 1601, 00:00:00 UTC */
+ guint8 timezone_index; /* index of time zone information */
+};
+
+/*
* The link-layer header on ATM packets.
*/
struct netmon_atm_hdr {
@@ -108,11 +132,39 @@ typedef struct {
time_t start_secs;
guint32 start_usecs;
guint8 version_major;
+ guint8 version_minor;
guint32 *frame_table;
guint32 frame_table_size;
guint current_frame;
} netmon_t;
+static const int netmon_encap[] = {
+ WTAP_ENCAP_UNKNOWN,
+ WTAP_ENCAP_ETHERNET,
+ WTAP_ENCAP_TOKEN_RING,
+ WTAP_ENCAP_FDDI_BITSWAPPED,
+ WTAP_ENCAP_ATM_PDUS, /* NDIS WAN - this is what's used for ATM */
+ WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk */
+ WTAP_ENCAP_UNKNOWN, /* NDIS "DIX" - should not occur */
+ WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET raw */
+ WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET 878.2 */
+ WTAP_ENCAP_UNKNOWN, /* NDIS ATM (no, this is NOT used for ATM) */
+ WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
+ WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
+};
+#define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
+
+/*
+ * Special link-layer types.
+ */
+#define NETMON_NET_LINUX_SLL 0xE071
+#define NETMON_NET_NETEVENT 0xFFE0
+#define NETMON_NET_NETWORK_INFO_EX 0xFFFB
+#define NETMON_NET_PAYLOAD_HEADER 0xFFFC
+#define NETMON_NET_NETWORK_INFO 0xFFFD
+#define NETMON_NET_DNS_CACHE 0xFFFE
+#define NETMON_NET_NETMON_FILTER 0xFFFF
+
static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
gint64 *data_offset);
static gboolean netmon_seek_read(wtap *wth, gint64 seek_off,
@@ -133,21 +185,6 @@ int netmon_open(wtap *wth, int *err, gchar **err_info)
char magic[sizeof netmon_1_x_magic];
struct netmon_hdr hdr;
int file_type;
- static const int netmon_encap[] = {
- WTAP_ENCAP_UNKNOWN,
- WTAP_ENCAP_ETHERNET,
- WTAP_ENCAP_TOKEN_RING,
- WTAP_ENCAP_FDDI_BITSWAPPED,
- WTAP_ENCAP_ATM_PDUS, /* NDIS WAN - this is what's used for ATM */
- WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk */
- WTAP_ENCAP_UNKNOWN, /* NDIS "DIX" - should not occur */
- WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET raw */
- WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET 878.2 */
- WTAP_ENCAP_UNKNOWN, /* NDIS ATM (no, this is NOT used for ATM) */
- WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
- WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
- };
- #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
struct tm tm;
int frame_table_offset;
guint32 frame_table_length;
@@ -219,10 +256,8 @@ int netmon_open(wtap *wth, int *err, gchar **err_info)
/* 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. */
- /* XXX - It would be better if we could set this to WTAP_ENCAP_PER_PACKET and show a message for
- * that, but the wtap_read() routine asserts on that value to catch errors. */
if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
- wth->file_encap = WTAP_ENCAP_UNKNOWN;
+ wth->file_encap = WTAP_ENCAP_PER_PACKET;
else
wth->file_encap = netmon_encap[hdr.network];
@@ -256,6 +291,7 @@ int netmon_open(wtap *wth, int *err, gchar **err_info)
netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
netmon->version_major = hdr.ver_major;
+ netmon->version_minor = hdr.ver_minor;
/*
* Get the offset of the frame index table.
@@ -334,13 +370,21 @@ static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
struct netmonrec_1_x_hdr hdr_1_x;
struct netmonrec_2_x_hdr hdr_2_x;
} hdr;
+ 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;
int hdr_size = 0;
+ int trlr_size = 0;
int rec_offset;
guint8 *data_ptr;
time_t secs;
guint32 usecs;
double t;
+ guint16 network;
+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;
@@ -354,9 +398,17 @@ static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
/* 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). */
+ so we don't want to do it unconditionally).
+
+ If the beginning of the current record is *before* the
+ current position, that's an error. */
rec_offset = netmon->frame_table[netmon->current_frame];
if (wth->data_offset != rec_offset) {
+ if (rec_offset < wth->data_offset) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("netmon: Record offset is in the middle of an earlier record");
+ return FALSE;
+ }
wth->data_offset = rec_offset;
if (file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1)
return FALSE;
@@ -485,6 +537,70 @@ static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
&wth->pseudo_header);
}
+ /*
+ * 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 = sizeof (struct netmonrec_2_3_trlr);
+ } else {
+ switch (netmon->version_minor) {
+
+ case 1:
+ trlr_size = sizeof (struct netmonrec_2_1_trlr);
+ break;
+
+ case 2:
+ trlr_size = sizeof (struct netmonrec_2_2_trlr);
+ break;
+
+ default:
+ trlr_size = sizeof (struct netmonrec_2_3_trlr);
+ break;
+ }
+ }
+ errno = WTAP_ERR_CANT_READ;
+
+ bytes_read = file_read(&trlr, 1, trlr_size, wth->fh);
+ if (bytes_read != trlr_size) {
+ *err = file_error(wth->fh);
+ if (*err == 0 && bytes_read != 0) {
+ *err = WTAP_ERR_SHORT_READ;
+ }
+ return FALSE;
+ }
+ wth->data_offset += trlr_size;
+
+ network = pletohs(trlr.trlr_2_1.network);
+ if (network >= NUM_NETMON_ENCAPS
+ || netmon_encap[network] == WTAP_ENCAP_UNKNOWN) {
+ 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. Read the next record.
+ */
+ goto again;
+ }
+ *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
+ network);
+ return FALSE;
+ }
+ wth->phdr.pkt_encap = netmon_encap[network];
+ }
+
return TRUE;
}