aboutsummaryrefslogtreecommitdiffstats
path: root/print.c
diff options
context:
space:
mode:
authorGilbert Ramirez <gram@alumni.rice.edu>2003-12-06 06:09:13 +0000
committerGilbert Ramirez <gram@alumni.rice.edu>2003-12-06 06:09:13 +0000
commit058ef64db8ce40909a18c91ab4805804362f80cb (patch)
tree767a7824daa712556971559e29e563658d643d51 /print.c
parent33b25ac15eac2e2cb4269377c41eada622c81fc1 (diff)
Add the ability to print packet dissections in PDML (an XML-based format)
to tethereal. It could be added to Ethereal, but the GUI changes to allow the user to select PDML as a print format have not been added. Provide a python module (EtherealXML.py) to help parse PDML. Provide a sample app (msnchat) which uses tethereal and EtherealXML.py to reconstruct MSN Chat sessions from packet capture files. It produces a nice HTML report of the chat sessions. Document tethereal's PDML and EtherealXML.py usage in doc/README.xml-output Update tethereal's manpage to reflect the new [-T pdml|ps|text] option svn path=/trunk/; revision=9180
Diffstat (limited to 'print.c')
-rw-r--r--print.c319
1 files changed, 311 insertions, 8 deletions
diff --git a/print.c b/print.c
index 07ab81d628..7e40e0e1fb 100644
--- a/print.c
+++ b/print.c
@@ -1,7 +1,7 @@
/* print.c
* Routines for printing packet analysis trees.
*
- * $Id: print.c,v 1.63 2003/12/04 10:59:33 guy Exp $
+ * $Id: print.c,v 1.64 2003/12/06 06:09:10 gram Exp $
*
* Gilbert Ramirez <gram@alumni.rice.edu>
*
@@ -40,8 +40,12 @@
#include "ps.h"
#include "util.h"
#include "packet-data.h"
+#include "packet-frame.h"
+
+#define PDML_VERSION "0"
static void proto_tree_print_node(proto_node *node, gpointer data);
+static void proto_tree_print_node_pdml(proto_node *node, gpointer data);
static void print_hex_data_buffer(FILE *fh, register const guchar *cp,
register guint length, char_enc encoding, gint format);
static void ps_clean_string(unsigned char *out, const unsigned char *in,
@@ -54,9 +58,12 @@ typedef struct {
gboolean print_all_levels;
gboolean print_hex_for_data;
char_enc encoding;
- gint format; /* text or PostScript */
+ gint format;
+ epan_dissect_t *edt;
} print_data;
+static void print_pdml_geninfo(proto_tree *tree, print_data *pdata);
+
FILE *open_print_dest(int to_file, const char *dest)
{
FILE *fh;
@@ -79,7 +86,9 @@ void close_print_dest(int to_file, FILE *fh)
pclose(fh);
}
-void proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
+
+void
+proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
FILE *fh)
{
print_data data;
@@ -94,8 +103,22 @@ void proto_tree_print(print_args_t *print_args, epan_dissect_t *edt,
/* If we're printing the entire packet in hex, don't
print uninterpreted data fields in hex as well. */
data.format = print_args->format;
+ data.edt = edt;
+
+ if (data.format == PR_FMT_PDML) {
+
+ fprintf(fh, "<packet>\n");
+
+ /* Print a "geninfo" protocol as required by PDML */
+ print_pdml_geninfo(edt->tree, &data);
+
+ proto_tree_children_foreach(edt->tree, proto_tree_print_node_pdml, &data);
- proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data);
+ fprintf(fh, "</packet>\n\n");
+ }
+ else {
+ proto_tree_children_foreach(edt->tree, proto_tree_print_node, &data);
+ }
}
/*
@@ -178,6 +201,269 @@ void proto_tree_print_node(proto_node *node, gpointer data)
}
}
+/* Print a string, escaping out certain characters that need to
+ * escaped out for XML. */
+static void
+print_escaped_xml(FILE *fh, char *unescaped_string)
+{
+ unsigned char *p;
+
+ for (p = unescaped_string; *p != '\0'; p++) {
+ switch (*p) {
+ case '&':
+ fputs("&amp;", fh);
+ break;
+ case '<':
+ fputs("&lt;", fh);
+ break;
+ case '>':
+ fputs("&gt;", fh);
+ break;
+ case '"':
+ fputs("&quot;", fh);
+ break;
+ default:
+ fputc(*p, fh);
+ }
+ }
+}
+
+static void
+print_field_hex_value(print_data *pdata, field_info *fi)
+{
+ int i;
+ const guint8 *pd;
+
+ /* Find the data for this field. */
+ pd = get_field_data(pdata->src_list, fi);
+
+ /* Print a simple hex dump */
+ for (i = 0 ; i < fi->length; i++) {
+ fprintf(pdata->fh, "%02x", pd[i]);
+ }
+}
+
+
+/* Print a tree's data, and any child nodes, as PDML */
+static void
+proto_tree_print_node_pdml(proto_node *node, gpointer data)
+{
+ field_info *fi = PITEM_FINFO(node);
+ print_data *pdata = (print_data*) data;
+ gchar *label_ptr;
+ gchar label_str[ITEM_LABEL_LENGTH];
+ char *dfilter_string;
+ int chop_len;
+ int i;
+
+ for (i = -1; i < pdata->level; i++) {
+ fputs(" ", pdata->fh);
+ }
+
+ /* Text label. It's printed as a field with no name. */
+ if (fi->hfinfo->id == hf_text_only) {
+ /* Get the text */
+ if (fi->rep) {
+ label_ptr = fi->rep->representation;
+ }
+ else {
+ label_ptr = "";
+ }
+
+ fputs("<field show=\"", pdata->fh);
+ print_escaped_xml(pdata->fh, label_ptr);
+
+ fprintf(pdata->fh, "\" size=\"%d", fi->length);
+ fprintf(pdata->fh, "\" pos=\"%d", fi->start);
+
+ fputs("\" value=\"", pdata->fh);
+ print_field_hex_value(pdata, fi);
+
+ if (node->first_child != NULL) {
+ fputs("\">\n", pdata->fh);
+ }
+ else {
+ fputs("\"/>\n", pdata->fh);
+ }
+ }
+ /* Uninterpreted data, i.e., the "Data" protocol, is
+ * printed as a field instead of a protocol. */
+ else if (fi->hfinfo->id == proto_data) {
+
+ fputs("<field name=\"data\" value=\"", pdata->fh);
+
+ print_field_hex_value(pdata, fi);
+
+ fputs("\"/>\n", pdata->fh);
+
+ }
+ /* Normal protocols and fields */
+ else {
+ if (fi->hfinfo->type == FT_PROTOCOL) {
+ fputs("<proto name=\"", pdata->fh);
+ }
+ else {
+ fputs("<field name=\"", pdata->fh);
+ }
+ print_escaped_xml(pdata->fh, fi->hfinfo->abbrev);
+
+ if (fi->rep) {
+ fputs("\" showname=\"", pdata->fh);
+ print_escaped_xml(pdata->fh, fi->rep->representation);
+ }
+ else {
+ label_ptr = label_str;
+ proto_item_fill_label(fi, label_str);
+ fputs("\" showname=\"", pdata->fh);
+ print_escaped_xml(pdata->fh, label_ptr);
+ }
+
+ fprintf(pdata->fh, "\" size=\"%d", fi->length);
+ fprintf(pdata->fh, "\" pos=\"%d", fi->start);
+/* fprintf(pdata->fh, "\" id=\"%d", fi->hfinfo->id);*/
+
+ if (fi->hfinfo->type != FT_PROTOCOL) {
+ /* Field */
+
+ /* XXX - this is a hack until we can juse call
+ * fvalue_to_string_repr() for *all* FT_* types. */
+ dfilter_string = proto_construct_dfilter_string(fi,
+ pdata->edt);
+ chop_len = strlen(fi->hfinfo->abbrev) + 4; /* for " == " */
+
+ /* XXX - Remove double-quotes. Again, once we can call
+ * fvalue_to_string_repr(), we can ask it not to
+ * produce the version for display-filters, and thus,
+ * no double-quotes. */
+ if (dfilter_string[strlen(dfilter_string)-1] == '"') {
+ dfilter_string[strlen(dfilter_string)-1] = '\0';
+ chop_len++;
+ }
+
+ fputs("\" show=\"", pdata->fh);
+ print_escaped_xml(pdata->fh, &dfilter_string[chop_len]);
+ }
+
+ if (fi->hfinfo->type != FT_PROTOCOL && fi->length > 0) {
+ fputs("\" value=\"", pdata->fh);
+ print_field_hex_value(pdata, fi);
+ }
+
+ if (node->first_child != NULL) {
+ fputs("\">\n", pdata->fh);
+ }
+ else if (fi->hfinfo->id == proto_data) {
+ fputs("\">\n", pdata->fh);
+ }
+ else {
+ fputs("\"/>\n", pdata->fh);
+ }
+ }
+
+ /* We always pring all levels for PDML. Recurse here. */
+ if (node->first_child != NULL) {
+ pdata->level++;
+ proto_tree_children_foreach(node,
+ proto_tree_print_node_pdml, pdata);
+ pdata->level--;
+ }
+
+ if (node->first_child != NULL) {
+ for (i = -1; i < pdata->level; i++) {
+ fputs(" ", pdata->fh);
+ }
+ if (fi->hfinfo->type == FT_PROTOCOL) {
+ fputs("</proto>\n", pdata->fh);
+ }
+ else {
+ fputs("</field>\n", pdata->fh);
+ }
+ }
+}
+
+/* Print info for a 'geninfo' pseudo-protocol. This is required by
+ * the PDML spec. The information is contained in Ethereal's 'frame' protocol,
+ * but we produce a 'geninfo' protocol in the PDML to conform to spec.
+ * The 'frame' protocol follows the 'geninfo' protocol in the PDML. */
+static void
+print_pdml_geninfo(proto_tree *tree, print_data *pdata)
+{
+ guint32 num, len, caplen;
+ nstime_t *timestamp;
+ GPtrArray *finfo_array;
+ field_info *frame_finfo;
+
+ /* Get frame protocol's finfo. */
+ finfo_array = proto_find_finfo(tree, proto_frame);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ frame_finfo = finfo_array->pdata[0];
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* frame.number --> geninfo.num */
+ finfo_array = proto_find_finfo(tree, hf_frame_number);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ num = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* frame.pkt_len --> geninfo.len */
+ finfo_array = proto_find_finfo(tree, hf_frame_packet_len);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ len = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* frame.cap_len --> geninfo.caplen */
+ finfo_array = proto_find_finfo(tree, hf_frame_capture_len);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ caplen = fvalue_get_integer(&((field_info*)finfo_array->pdata[0])->value);
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* frame.time --> geninfo.timestamp */
+ finfo_array = proto_find_finfo(tree, hf_frame_arrival_time);
+ if (g_ptr_array_len(finfo_array) < 1) {
+ return;
+ }
+ timestamp = fvalue_get(&((field_info*)finfo_array->pdata[0])->value);
+ g_ptr_array_free(finfo_array, FALSE);
+
+ /* Print geninfo start */
+ fprintf(pdata->fh,
+" <proto name=\"geninfo\" pos=\"1\" showname=\"General information\" size=\"%u\">\n",
+ frame_finfo->length);
+
+ /* Print geninfo.num */
+ fprintf(pdata->fh,
+" <field name=\"num\" pos=\"1\" show=\"%u\" showname=\"Number\" value=\"%x\" size=\"%u\"/>\n",
+ num, num, frame_finfo->length);
+
+ /* Print geninfo.len */
+ fprintf(pdata->fh,
+" <field name=\"len\" pos=\"1\" show=\"%u\" showname=\"Packet Length\" value=\"%x\" size=\"%u\"/>\n",
+ len, len, frame_finfo->length);
+
+ /* Print geninfo.caplen */
+ fprintf(pdata->fh,
+" <field name=\"caplen\" pos=\"1\" show=\"%u\" showname=\"Captured Length\" value=\"%x\" size=\"%u\"/>\n",
+ caplen, caplen, frame_finfo->length);
+
+ /* Print geninfo.timestamp */
+ fprintf(pdata->fh,
+" <field name=\"timestamp\" pos=\"1\" show=\"%s\" showname=\"Captured Time\" value=\"%d.%09d\" size=\"%u\"/>\n",
+ abs_time_to_str(timestamp), (int) timestamp->secs, timestamp->nsecs, frame_finfo->length);
+
+ /* Print geninfo end */
+ fprintf(pdata->fh,
+" </proto>\n");
+}
+
+
void print_hex_data(FILE *fh, gint format, epan_dissect_t *edt)
{
gboolean multiple_sources;
@@ -346,19 +632,32 @@ void ps_clean_string(unsigned char *out, const unsigned char *in,
}
}
-void print_preamble(FILE *fh, gint format)
+/* Some formats need stuff at the beginning of the output */
+void
+print_preamble(FILE *fh, gint format)
{
if (format == PR_FMT_PS)
print_ps_preamble(fh);
+ else if (format == PR_FMT_PDML) {
+ fputs("<?xml version=\"1.0\"?>\n", fh);
+ fputs("<pdml version=\"" PDML_VERSION "\" ", fh);
+ fprintf(fh, "creator=\"%s/%s\">\n", PACKAGE, VERSION);
+ }
}
-void print_finale(FILE *fh, gint format)
+/* Some formats need stuff at the end of the output */
+void
+print_finale(FILE *fh, gint format)
{
if (format == PR_FMT_PS)
print_ps_finale(fh);
+ else if (format == PR_FMT_PDML) {
+ fputs("</pdml>\n", fh);
+ }
}
-void print_line(FILE *fh, int indent, gint format, char *line)
+void
+print_line(FILE *fh, int indent, gint format, char *line)
{
char space[MAX_INDENT+1];
int i;
@@ -368,7 +667,8 @@ void print_line(FILE *fh, int indent, gint format, char *line)
if (format == PR_FMT_PS) {
ps_clean_string(psbuffer, line, MAX_PS_LINE_LENGTH);
fprintf(fh, "%d (%s) putline\n", indent, psbuffer);
- } else {
+ }
+ else if (format == PR_FMT_TEXT) {
/* Prepare the tabs for printing, depending on tree level */
num_spaces = indent * 4;
if (num_spaces > MAX_INDENT) {
@@ -384,4 +684,7 @@ void print_line(FILE *fh, int indent, gint format, char *line)
fputs(line, fh);
putc('\n', fh);
}
+ else {
+ g_assert_not_reached();
+ }
}