diff options
author | Michael Mann <mmann78@netscape.net> | 2017-08-25 15:29:17 -0400 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2017-08-30 06:10:17 +0000 |
commit | 52823805b29a44a83eacd0e5b415b11227ec313b (patch) | |
tree | f0a7d33933a3e7aee0baedd393d40489a4feb59c /wiretap | |
parent | 32b27bf19d181e4b2b227d13450a9dee9582af2c (diff) |
Add support for reading comments in Network Monitor files
The NetMon wiretap reads the title and description comment fields from a
NetMon file and saves it in the wiretap private structure. Then when
it's time to make a frame, the comment fields are added to a NetMon
pseudoheader with a new WTAP ENCAP type, with the potential for netmon
pseudoheader to contain pseudoheader data from "base" wiretap. Then the
netmon_header dissector displays the comment fields and passes any "base"
wiretap pseudoheader data when calling the wtap_encap dissector table
that the frame dissector normally calls.
Bug: 4225
Change-Id: I8f772bc9494364c98434c78b61eb5a64012ff3b9
Reviewed-on: https://code.wireshark.org/review/23210
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'wiretap')
-rw-r--r-- | wiretap/netmon.c | 275 | ||||
-rw-r--r-- | wiretap/wtap.c | 3 | ||||
-rw-r--r-- | wiretap/wtap.h | 17 |
3 files changed, 273 insertions, 22 deletions
diff --git a/wiretap/netmon.c b/wiretap/netmon.c index 3f46b49ffb..8238e955f5 100644 --- a/wiretap/netmon.c +++ b/wiretap/netmon.c @@ -120,6 +120,22 @@ struct netmonrec_2_3_trlr { 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 */ + guint32 titleLength; /* Number of bytes in the comment title. Must be greater than zero. */ + 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; +}; + /* * The link-layer header on ATM packets. */ @@ -131,13 +147,14 @@ struct netmon_atm_hdr { }; 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; + guint current_frame; } netmon_t; /* @@ -180,11 +197,19 @@ static gboolean netmon_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr, 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 void netmon_sequential_close(wtap *wth); +static void netmon_close(wtap *wth); static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, const guint8 *pd, int *err, gchar **err_info); static gboolean netmon_dump_finish(wtap_dumper *wdh, int *err); +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); +} + wtap_open_return_val netmon_open(wtap *wth, int *err, gchar **err_info) { char magic[MAGIC_SIZE]; @@ -195,6 +220,10 @@ wtap_open_return_val netmon_open(wtap *wth, int *err, gchar **err_info) guint32 frame_table_length; guint32 frame_table_size; guint32 *frame_table; + guint32 comment_table_offset; + guint32 comment_table_size; + GHashTable* comment_table; + struct netmonrec_comment* comment_rec; #ifdef WORDS_BIGENDIAN unsigned int i; #endif @@ -244,11 +273,11 @@ wtap_open_return_val netmon_open(wtap *wth, int *err, gchar **err_info) /* 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; /* 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. */ @@ -290,18 +319,15 @@ wtap_open_return_val netmon_open(wtap *wth, int *err, gchar **err_info) 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. + * Get the offset and length of the comment index table. */ - frame_table_offset = pletoh32(&hdr.frametableoffset); + comment_table_offset = pletoh32(&hdr.commentdataoffset); + comment_table_size = pletoh32(&hdr.commentdatalength); /* * It appears that some NetMon 2.x files don't have the @@ -350,6 +376,44 @@ wtap_open_return_val netmon_open(wtap *wth, int *err, gchar **err_info) if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -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 (file_seek(wth->fh, comment_table_offset, SEEK_SET, err) == -1) { + 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; + } + } + 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 */ @@ -363,6 +427,115 @@ wtap_open_return_val netmon_open(wtap *wth, int *err, gchar **err_info) netmon->frame_table_size = frame_table_size; netmon->frame_table = frame_table; + 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 */ + g_free(frame_table); + 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_free(frame_table); + 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_free(frame_table); + g_hash_table_destroy(comment_table); + return WTAP_OPEN_ERROR; + } + + while (comment_table_size > 16) { + struct netmonrec_comment_header comment_header; + guint32 desc_length; + + /* Read the first 12 bytes of the structure */ + if (!wtap_read_bytes(wth->fh, &comment_header, 12, err, err_info)) { + g_free(frame_table); + g_hash_table_destroy(comment_table); + return WTAP_OPEN_ERROR; + } + comment_table_size -= 12; + + /* Make sure comment size is sane */ + if (pletoh32(&comment_header.titleLength) == 0) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup("netmon: comment title size can't be 0"); + g_free(frame_table); + g_hash_table_destroy(comment_table); + return WTAP_OPEN_ERROR; + } + if (pletoh32(&comment_header.titleLength) > comment_table_size) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("netmon: comment title size is %u, which is larger than the entire comment section (%d)", + pletoh32(&comment_header.titleLength), comment_table_size); + g_free(frame_table); + g_hash_table_destroy(comment_table); + return WTAP_OPEN_ERROR; + } + + comment_rec = g_new(struct netmonrec_comment, 1); + comment_rec->numFramePerComment = pletoh32(&comment_header.numFramePerComment); + comment_rec->frameOffset = pletoh32(&comment_header.frameOffset); + comment_rec->titleLength = pletoh32(&comment_header.titleLength); + comment_rec->title = (guint8*)g_malloc(comment_rec->titleLength); + + g_hash_table_insert(comment_table, GUINT_TO_POINTER(comment_rec->frameOffset), comment_rec); + + /* Read the comment title */ + if (!wtap_read_bytes(wth->fh, comment_rec->title, comment_rec->titleLength, err, err_info)) { + g_free(frame_table); + g_hash_table_destroy(comment_table); + return WTAP_OPEN_ERROR; + } + comment_table_size -= comment_rec->titleLength; + + if (comment_table_size < 4) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup("netmon: corrupt comment section"); + g_free(frame_table); + g_hash_table_destroy(comment_table); + return WTAP_OPEN_ERROR; + } + + if (!wtap_read_bytes(wth->fh, &desc_length, 4, err, err_info)) { + g_free(frame_table); + 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 entire comment section (%d)", + comment_rec->descLength, comment_table_size); + g_free(frame_table); + 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_free(frame_table); + g_hash_table_destroy(comment_table); + return WTAP_OPEN_ERROR; + } + + comment_table_size -= comment_rec->descLength; + } + } + netmon->comment_table = comment_table; + } + #ifdef WORDS_BIGENDIAN /* * OK, now byte-swap the frame table. @@ -467,6 +640,7 @@ netmon_process_record(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr, } trlr; guint16 network; int pkt_encap; + struct netmonrec_comment* comment_rec = NULL; /* Read record header. */ switch (netmon->version_major) { @@ -754,6 +928,62 @@ netmon_process_record(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr, } netmon_set_pseudo_header_info(phdr, 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 + */ + switch (phdr->pkt_encap) + { + case WTAP_ENCAP_ATM_PDUS: + memcpy(&temp_header.atm, &phdr->pseudo_header.atm, sizeof(temp_header.atm)); + break; + case WTAP_ENCAP_ETHERNET: + memcpy(&temp_header.eth, &phdr->pseudo_header.eth, sizeof(temp_header.eth)); + break; + case WTAP_ENCAP_IEEE_802_11_NETMON: + memcpy(&temp_header.ieee_802_11, &phdr->pseudo_header.ieee_802_11, sizeof(temp_header.ieee_802_11)); + break; + } + memset(&phdr->pseudo_header.netmon, 0, sizeof(phdr->pseudo_header.netmon)); + + /* Save the current encapsulation type to the NetMon pseudoheader */ + phdr->pseudo_header.netmon.sub_encap = phdr->pkt_encap; + + /* Copy the comment data */ + phdr->pseudo_header.netmon.titleLength = comment_rec->titleLength; + phdr->pseudo_header.netmon.title = comment_rec->title; + phdr->pseudo_header.netmon.descLength = comment_rec->descLength; + phdr->pseudo_header.netmon.description = comment_rec->description; + + /* Copy the saved pseudoheaders to the netmon pseudoheader structure */ + switch (phdr->pkt_encap) + { + case WTAP_ENCAP_ATM_PDUS: + memcpy(&phdr->pseudo_header.netmon.subheader.atm, &temp_header.atm, sizeof(temp_header.atm)); + break; + case WTAP_ENCAP_ETHERNET: + memcpy(&phdr->pseudo_header.netmon.subheader.eth, &temp_header.eth, sizeof(temp_header.eth)); + break; + case WTAP_ENCAP_IEEE_802_11_NETMON: + memcpy(&phdr->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 */ + phdr->pkt_encap = WTAP_ENCAP_NETMON_HEADER; + } + return SUCCESS; } @@ -767,10 +997,6 @@ static gboolean netmon_read(wtap *wth, int *err, gchar **err_info, for (;;) { /* 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 FALSE; } @@ -865,7 +1091,7 @@ netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, /* 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; @@ -873,6 +1099,11 @@ netmon_sequential_close(wtap *wth) 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; + } } typedef struct { diff --git a/wiretap/wtap.c b/wiretap/wtap.c index d606cb57d5..4e57ece6db 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -935,6 +935,9 @@ static struct encap_type_info encap_table_base[] = { /* WTAP_ENCAP_NETMON_NET_NETEVENT */ { "Network Monitor Network Event", "netmon_event" }, + + /* WTAP_ENCAP_NETMON_HEADER */ + { "Network Monitor Header", "netmon_header" }, }; WS_DLL_LOCAL diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 7959b0bfc6..00bafcde19 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -275,6 +275,7 @@ extern "C" { #define WTAP_ENCAP_VSOCK 185 #define WTAP_ENCAP_NORDIC_BLE 186 #define WTAP_ENCAP_NETMON_NET_NETEVENT 187 +#define WTAP_ENCAP_NETMON_HEADER 188 /* After adding new item here, please also add new item to encap_table_base array */ #define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types() @@ -1147,6 +1148,21 @@ struct sysdig_event_phdr { /* ... Event ... */ }; +/* Packet "pseudo-header" information for header data from NetMon files. */ + +struct netmon_phdr { + guint32 titleLength; /* Number of bytes in the comment title */ + guint8* title; /* Comment title */ + guint32 descLength; /* Number of bytes in the comment description */ + guint8* description; /* Comment description */ + guint sub_encap; /* "Real" encap value for the record that will be used once pseudo header data is display */ + union sub_wtap_pseudo_header { + struct eth_phdr eth; + struct atm_phdr atm; + struct ieee_802_11_phdr ieee_802_11; + } subheader; +}; + /* Pseudo-header for file-type-specific records */ struct ft_specific_record_phdr { guint record_type; /* the type of record this is */ @@ -1179,6 +1195,7 @@ union wtap_pseudo_header { struct llcp_phdr llcp; struct logcat_phdr logcat; struct sysdig_event_phdr sysdig_event; + struct netmon_phdr netmon; struct ft_specific_record_phdr ftsrec; }; |