# include "config.h"
#endif
-/* #include <stdio.h> */
#include <string.h>
#include <glib.h>
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/expert.h>
+#include <epan/stats_tree.h>
#define TYPE_HOST 0x0000
#define TYPE_TIME 0x0001
gint message_len;
} notify_data_t;
+struct string_counter_s;
+typedef struct string_counter_s string_counter_t;
+struct string_counter_s
+{
+ gchar *string;
+ gint count;
+ string_counter_t *next;
+};
+
+typedef struct tap_data_s {
+ gint values_num;
+
+ string_counter_t *hosts;
+ string_counter_t *plugins;
+ string_counter_t *types;
+} tap_data_t;
+
static const value_string part_names[] = {
{ TYPE_VALUES, "VALUES" },
{ TYPE_TIME, "TIME" },
#define TYPE_VALUE_COUNTER 0x00
#define TYPE_VALUE_GAUGE 0x01
+#define TYPE_VALUE_DERIVE 0x02
+#define TYPE_VALUE_ABSOLUTE 0x03
static const value_string valuetypenames[] = {
{ TYPE_VALUE_COUNTER, "COUNTER" },
{ TYPE_VALUE_GAUGE, "GAUGE" },
+ { TYPE_VALUE_DERIVE, "DERIVE" },
+ { TYPE_VALUE_ABSOLUTE, "ABSOLUTE" },
{ 0, NULL }
};
};
#define UDP_PORT_COLLECTD 25826
-static gint collectd_udp_port = UDP_PORT_COLLECTD;
+static guint collectd_udp_port = UDP_PORT_COLLECTD;
static gint proto_collectd = -1;
+static gint tap_collectd = -1;
static gint hf_collectd_type = -1;
static gint hf_collectd_length = -1;
static gint hf_collectd_val_type = -1;
static gint hf_collectd_val_counter = -1;
static gint hf_collectd_val_gauge = -1;
+static gint hf_collectd_val_derive = -1;
+static gint hf_collectd_val_absolute = -1;
static gint hf_collectd_val_unknown = -1;
static gint hf_collectd_data_severity = -1;
static gint hf_collectd_data_message = -1;
static gint ett_collectd_invalid_length = -1;
static gint ett_collectd_unknown = -1;
+static gint st_collectd_packets = -1;
+static gint st_collectd_values = -1;
+static gint st_collectd_values_hosts = -1;
+static gint st_collectd_values_plugins = -1;
+static gint st_collectd_values_types = -1;
+
/* Prototype for the handoff function */
void proto_reg_handoff_collectd (void);
+static void
+collectd_stats_tree_init (stats_tree *st)
+{
+ st_collectd_packets = stats_tree_create_node (st, "Packets", 0, FALSE);
+ st_collectd_values = stats_tree_create_node (st, "Values", 0, TRUE);
+
+ st_collectd_values_hosts = stats_tree_create_pivot (st, "By host",
+ st_collectd_values);
+ st_collectd_values_plugins = stats_tree_create_pivot (st, "By plugin",
+ st_collectd_values);
+ st_collectd_values_types = stats_tree_create_pivot (st, "By type",
+ st_collectd_values);
+} /* void collectd_stats_tree_init */
+
+static int
+collectd_stats_tree_packet (stats_tree *st, packet_info *pinfo _U_,
+ epan_dissect_t *edt _U_, const void *user_data)
+{
+ const tap_data_t *td;
+ string_counter_t *sc;
+
+ td = user_data;
+ if (td == NULL)
+ return (-1);
+
+ tick_stat_node (st, "Packets", 0, FALSE);
+ increase_stat_node (st, "Values", 0, TRUE, td->values_num);
+
+ for (sc = td->hosts; sc != NULL; sc = sc->next)
+ {
+ gint i;
+ for (i = 0; i < sc->count; i++)
+ stats_tree_tick_pivot (st, st_collectd_values_hosts,
+ sc->string);
+ }
+
+ for (sc = td->plugins; sc != NULL; sc = sc->next)
+ {
+ gint i;
+ for (i = 0; i < sc->count; i++)
+ stats_tree_tick_pivot (st, st_collectd_values_plugins,
+ sc->string);
+ }
+
+ for (sc = td->types; sc != NULL; sc = sc->next)
+ {
+ gint i;
+ for (i = 0; i < sc->count; i++)
+ stats_tree_tick_pivot (st, st_collectd_values_types,
+ sc->string);
+ }
+
+ return (1);
+} /* int collectd_stats_tree_packet */
+
+static void
+collectd_stats_tree_register (void)
+{
+ stats_tree_register ("collectd", "collectd", "Collectd", 0,
+ collectd_stats_tree_packet,
+ collectd_stats_tree_init, NULL);
+} /* void register_collectd_stat_trees */
+
static int
dissect_collectd_string (tvbuff_t *tvb, packet_info *pinfo, gint type_hf,
gint offset, gint *ret_offset, gint *ret_length,
value_tree = proto_item_add_subtree (pi,
ett_collectd_valinfo);
proto_tree_add_item (value_tree, hf_collectd_val_type,
- tvb, value_type_offset, 1, FALSE);
+ tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item (value_tree,
hf_collectd_val_counter, tvb,
- value_offset, 8, FALSE);
+ value_offset, 8, ENC_BIG_ENDIAN);
break;
}
value_tree = proto_item_add_subtree (pi,
ett_collectd_valinfo);
proto_tree_add_item (value_tree, hf_collectd_val_type,
- tvb, value_type_offset, 1, FALSE);
+ tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
/* Set the `little endian' flag to TRUE here, because
* collectd stores doubles in x86 representation. */
proto_tree_add_item (value_tree, hf_collectd_val_gauge,
- tvb, value_offset, 8, TRUE);
+ tvb, value_offset, 8, ENC_LITTLE_ENDIAN);
+ break;
+ }
+
+ case TYPE_VALUE_DERIVE:
+ {
+ gint64 val64;
+
+ val64 = tvb_get_ntoh64 (tvb, value_offset);
+ pi = proto_tree_add_text (values_tree, tvb, msg_off + 6,
+ val_cnt * 9,
+ "Derive: %"G_GINT64_MODIFIER"i", val64);
+
+ value_tree = proto_item_add_subtree (pi,
+ ett_collectd_valinfo);
+ proto_tree_add_item (value_tree, hf_collectd_val_type,
+ tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item (value_tree,
+ hf_collectd_val_derive, tvb,
+ value_offset, 8, ENC_BIG_ENDIAN);
+ break;
+ }
+
+ case TYPE_VALUE_ABSOLUTE:
+ {
+ guint64 val64;
+
+ val64 = tvb_get_ntoh64 (tvb, value_offset);
+ pi = proto_tree_add_text (values_tree, tvb, msg_off + 6,
+ val_cnt * 9,
+ "Absolute: %"G_GINT64_MODIFIER"u", val64);
+
+ value_tree = proto_item_add_subtree (pi,
+ ett_collectd_valinfo);
+ proto_tree_add_item (value_tree, hf_collectd_val_type,
+ tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item (value_tree,
+ hf_collectd_val_absolute, tvb,
+ value_offset, 8, ENC_BIG_ENDIAN);
break;
}
value_tree = proto_item_add_subtree (pi,
ett_collectd_valinfo);
proto_tree_add_item (value_tree, hf_collectd_val_type,
- tvb, value_type_offset, 1, FALSE);
+ tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item (value_tree, hf_collectd_val_unknown,
- tvb, value_offset, 8, FALSE);
+ tvb, value_offset, 8, ENC_BIG_ENDIAN);
break;
}
} /* switch (value_type) */
proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
pi = proto_tree_add_item (pt, hf_collectd_data_valcnt, tvb,
- offset + 4, 2, FALSE);
+ offset + 4, 2, ENC_BIG_ENDIAN);
if (values_count != corrected_values_count)
expert_add_info_format (pinfo, pi, PI_MALFORMED, PI_WARN,
"Number of values and length of part do not match. "
pi = proto_tree_add_text (pt, tvb, offset + 6, length - 6, "Dispatch simulation");
pt = proto_item_add_subtree(pi, ett_collectd_dispatch);
proto_tree_add_text (pt, tvb, vdispatch->host_off, vdispatch->host_len,
- "Host: %s", vdispatch->host);
+ "Host: %s", vdispatch->host ? vdispatch->host : "(null)");
proto_tree_add_text (pt, tvb, vdispatch->plugin_off,
vdispatch->plugin_len,
- "Plugin: %s", vdispatch->plugin);
+ "Plugin: %s", vdispatch->plugin ? vdispatch->plugin : "(null)");
if (vdispatch->plugin_instance)
proto_tree_add_text (pt, tvb, vdispatch->plugin_instance_off,
vdispatch->plugin_instance_len,
"Plugin instance: %s", vdispatch->plugin_instance);
proto_tree_add_text (pt, tvb, vdispatch->type_off, vdispatch->type_len,
- "Type: %s", vdispatch->type);
+ "Type: %s", vdispatch->type ? vdispatch->type : "(null)");
if (vdispatch->type_instance)
proto_tree_add_text(pt, tvb, vdispatch->type_instance_off,
vdispatch->type_instance_len,
"Type instance: %s", vdispatch->type_instance);
proto_tree_add_text (pt, tvb, vdispatch->time_off, 8,
"Timestamp: %"G_GINT64_MODIFIER"u (%s)",
- vdispatch->time, vdispatch->time_str);
+ vdispatch->time, vdispatch->time_str ? vdispatch->time_str : "(null)");
proto_tree_add_text (pt, tvb, vdispatch->interval_off, 8,
"Interval: %"G_GINT64_MODIFIER"u",
vdispatch->interval);
proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
length);
- proto_tree_add_item (pt, hf_collectd_data_sighash, tvb, offset + 4, 32, FALSE);
- proto_tree_add_item (pt, hf_collectd_data_username, tvb, offset + 36, length - 36, FALSE);
+ proto_tree_add_item (pt, hf_collectd_data_sighash, tvb, offset + 4, 32, ENC_NA);
+ proto_tree_add_item (pt, hf_collectd_data_username, tvb, offset + 36, length - 36, ENC_ASCII|ENC_NA);
return (0);
} /* int dissect_collectd_signature */
proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
proto_tree_add_uint (pt, hf_collectd_data_username_len, tvb, offset + 4, 2, username_length);
- proto_tree_add_item (pt, hf_collectd_data_username, tvb, offset + 6, username_length, FALSE);
+ proto_tree_add_item (pt, hf_collectd_data_username, tvb, offset + 6, username_length, ENC_ASCII|ENC_NA);
proto_tree_add_item (pt, hf_collectd_data_initvec, tvb,
- offset + (6 + username_length), 16, FALSE);
+ offset + (6 + username_length), 16, ENC_NA);
proto_tree_add_item (pt, hf_collectd_data_encrypted, tvb,
offset + (22 + username_length),
- length - (22 + username_length), FALSE);
+ length - (22 + username_length), ENC_NA);
return (0);
} /* int dissect_collectd_encrypted */
+static int
+stats_account_string (string_counter_t **ret_list, const gchar *new_value)
+{
+ string_counter_t *entry;
+
+ if (ret_list == NULL)
+ return (-1);
+
+ if (new_value == NULL)
+ new_value = "(null)";
+
+ for (entry = *ret_list; entry != NULL; entry = entry->next)
+ if (strcmp (new_value, entry->string) == 0)
+ {
+ entry->count++;
+ return (0);
+ }
+
+ entry = ep_alloc0 (sizeof (*entry));
+ entry->string = ep_strdup (new_value);
+ entry->count = 1;
+ entry->next = *ret_list;
+
+ *ret_list = entry;
+
+ return (0);
+}
+
static void
dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
+ static tap_data_t tap_data;
+
gint offset;
gint size;
gchar *pkt_host = NULL;
size = tvb_reported_length(tvb);
/* create the collectd protocol tree */
- pi = proto_tree_add_item(tree, proto_collectd, tvb, 0, -1, FALSE);
+ pi = proto_tree_add_item(tree, proto_collectd, tvb, 0, -1, ENC_NA);
collectd_tree = proto_item_add_subtree(pi, ett_collectd);
+ memset (&tap_data, 0, sizeof (tap_data));
+
status = 0;
while ((size > 0) && (status == 0))
{
switch (part_type) {
case TYPE_HOST:
+ vdispatch.host = tvb_get_ephemeral_string (tvb,
+ offset + 4, part_length - 4);
if (pkt_host == NULL)
- pkt_host = tvb_get_ephemeral_string(tvb, offset+4, part_length-4);
+ pkt_host = vdispatch.host;
break;
case TYPE_TIME:
break;
case TYPE_PLUGIN:
+ vdispatch.plugin = tvb_get_ephemeral_string (tvb,
+ offset + 4, part_length - 4);
pkt_plugins++;
break;
case TYPE_PLUGIN_INSTANCE:
break;
case TYPE_TYPE:
+ vdispatch.type = tvb_get_ephemeral_string (tvb,
+ offset + 4, part_length - 4);
break;
case TYPE_TYPE_INSTANCE:
break;
case TYPE_INTERVAL:
break;
case TYPE_VALUES:
+ {
pkt_values++;
+
+ tap_data.values_num++;
+ stats_account_string (&tap_data.hosts,
+ vdispatch.host);
+ stats_account_string (&tap_data.plugins,
+ vdispatch.plugin);
+ stats_account_string (&tap_data.types,
+ vdispatch.type);
+
break;
+ }
case TYPE_MESSAGE:
pkt_messages++;
break;
pkt_errors++;
else
{
- vdispatch.time_str = abs_time_secs_to_str ((time_t) vdispatch.time);
+ vdispatch.time_str = abs_time_secs_to_str ((time_t) vdispatch.time, ABSOLUTE_TIME_LOCAL, TRUE);
ndispatch.time = vdispatch.time;
ndispatch.time_str = vdispatch.time_str;
proto_item_set_text (pi, "collectd TIME segment: %"G_GINT64_MODIFIER"u (%s)",
- vdispatch.time, vdispatch.time_str);
+ vdispatch.time, vdispatch.time_str ? vdispatch.time_str : "(null)");
}
break;
else
pkt_values++;
+ tap_data.values_num++;
+ stats_account_string (&tap_data.hosts,
+ vdispatch.host);
+ stats_account_string (&tap_data.plugins,
+ vdispatch.plugin);
+ stats_account_string (&tap_data.types,
+ vdispatch.type);
+
break;
}
pt = proto_item_add_subtree(pi, ett_collectd_dispatch);
proto_tree_add_text (pt, tvb, ndispatch.host_off,
ndispatch.host_len,
- "Host: %s", ndispatch.host);
+ "Host: %s", ndispatch.host ? ndispatch.host : "(null)");
proto_tree_add_text (pt, tvb, ndispatch.time_off, 8,
"Timestamp: %"G_GINT64_MODIFIER"u (%s)",
- ndispatch.time, ndispatch.time_str);
+ ndispatch.time, ndispatch.time_str ? ndispatch.time_str : "(null)");
proto_tree_add_text (pt, tvb, ndispatch.severity_off, 8,
"Severity: %s (%#"G_GINT64_MODIFIER"x)",
val_to_str((gint32)ndispatch.severity, severity_names, "UNKNOWN"),
proto_tree_add_uint (pt, hf_collectd_length, tvb,
offset + 2, 2, part_length);
proto_tree_add_item (pt, hf_collectd_data, tvb,
- offset + 4, part_length - 4, FALSE);
+ offset + 4, part_length - 4, ENC_NA);
expert_add_info_format (pinfo, pi,
PI_UNDECODED, PI_NOTE,
pkt_values, plurality (pkt_values, " ", "s"),
pkt_plugins, plurality (pkt_plugins, ", ", "s,"),
pkt_messages, plurality (pkt_messages, "", "s"));
+
+ /* Dispatch tap data. */
+ tap_queue_packet (tap_collectd, pinfo, &tap_data);
} /* void dissect_collectd */
void proto_register_collectd(void)
NULL, 0x0, NULL, HFILL }
},
{ &hf_collectd_data,
- { "Payload", "collectd.data", FT_BYTES, BASE_HEX,
+ { "Payload", "collectd.data", FT_BYTES, BASE_NONE,
NULL, 0x0, NULL, HFILL }
},
{ &hf_collectd_data_host,
{ "Gauge value", "collectd.val.gauge", FT_DOUBLE, BASE_NONE,
NULL, 0x0, NULL, HFILL }
},
+ { &hf_collectd_val_derive,
+ { "Derive value", "collectd.val.derive", FT_INT64, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }
+ },
+ { &hf_collectd_val_absolute,
+ { "Absolute value", "collectd.val.absolute", FT_UINT64, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }
+ },
{ &hf_collectd_val_unknown,
{ "Value of unknown type", "collectd.val.unknown", FT_UINT64, BASE_HEX,
NULL, 0x0, NULL, HFILL }
NULL, 0x0, NULL, HFILL }
},
{ &hf_collectd_data_sighash,
- { "Signature", "collectd.data.sighash", FT_BYTES, BASE_HEX,
+ { "Signature", "collectd.data.sighash", FT_BYTES, BASE_NONE,
NULL, 0x0, NULL, HFILL }
},
{ &hf_collectd_data_initvec,
- { "Init vector", "collectd.data.initvec", FT_BYTES, BASE_HEX,
+ { "Init vector", "collectd.data.initvec", FT_BYTES, BASE_NONE,
NULL, 0x0, NULL, HFILL }
},
{ &hf_collectd_data_username_len,
NULL, 0x0, NULL, HFILL }
},
{ &hf_collectd_data_encrypted,
- { "Encrypted data", "collectd.data.encrypted", FT_BYTES, BASE_HEX,
+ { "Encrypted data", "collectd.data.encrypted", FT_BYTES, BASE_NONE,
NULL, 0x0, NULL, HFILL }
},
};
proto_register_field_array(proto_collectd, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+ tap_collectd = register_tap ("collectd");
+
/*
* Create an unsigned integer preference to allow the user to specify the
* UDP port on which to capture DIS packets.
/* Change the dissector registration if the preferences have been
* changed. */
if (registered_udp_port != -1)
- dissector_delete ("udp.port", registered_udp_port,
+ dissector_delete_uint ("udp.port", registered_udp_port,
collectd_handle);
- dissector_add ("udp.port", collectd_udp_port, collectd_handle);
+ dissector_add_uint ("udp.port", collectd_udp_port, collectd_handle);
registered_udp_port = collectd_udp_port;
+ if (first_run)
+ collectd_stats_tree_register ();
+
first_run = FALSE;
} /* void proto_reg_handoff_collectd */