Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-collectd.c
blobf74e461d0b23342b14c7302e5031b5fd0dd36640
1 /* packet-collectd.c
2 * Routines for collectd (http://collectd.org/) network plugin dissection
4 * Copyright 2008 Bruno Premont <bonbons at linux-vserver.org>
5 * Copyright 2009-2013 Florian Forster <octo at collectd.org>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "config.h"
16 #include <epan/packet.h>
17 #include <epan/expert.h>
18 #include <epan/stats_tree.h>
19 #include <epan/to_str.h>
21 #include <wsutil/str_util.h>
23 #define STR_NONNULL(str) ((str) ? ((const char*)str) : "(null)")
25 #define TYPE_HOST 0x0000
26 #define TYPE_TIME 0x0001
27 #define TYPE_TIME_HR 0x0008
28 #define TYPE_PLUGIN 0x0002
29 #define TYPE_PLUGIN_INSTANCE 0x0003
30 #define TYPE_TYPE 0x0004
31 #define TYPE_TYPE_INSTANCE 0x0005
32 #define TYPE_VALUES 0x0006
33 #define TYPE_INTERVAL 0x0007
34 #define TYPE_INTERVAL_HR 0x0009
35 #define TYPE_MESSAGE 0x0100
36 #define TYPE_SEVERITY 0x0101
37 #define TYPE_SIGN_SHA256 0x0200
38 #define TYPE_ENCR_AES256 0x0210
40 void proto_register_collectd(void);
42 static dissector_handle_t collectd_handle;
44 typedef struct value_data_s {
45 const uint8_t *host;
46 int host_off;
47 int host_len;
48 uint64_t time_value;
49 int time_off;
50 uint64_t interval;
51 int interval_off;
52 const uint8_t *plugin;
53 int plugin_off;
54 int plugin_len;
55 const uint8_t *plugin_instance;
56 int plugin_instance_off;
57 int plugin_instance_len;
58 const uint8_t *type;
59 int type_off;
60 int type_len;
61 const uint8_t *type_instance;
62 int type_instance_off;
63 int type_instance_len;
64 } value_data_t;
66 typedef struct notify_data_s {
67 const uint8_t *host;
68 int host_off;
69 int host_len;
70 uint64_t time_value;
71 int time_off;
72 uint64_t severity;
73 int severity_off;
74 const uint8_t *message;
75 int message_off;
76 int message_len;
77 } notify_data_t;
79 struct string_counter_s;
80 typedef struct string_counter_s string_counter_t;
81 struct string_counter_s
83 const char *string;
84 int count;
85 string_counter_t *next;
88 typedef struct tap_data_s {
89 int values_num;
91 string_counter_t *hosts;
92 string_counter_t *plugins;
93 string_counter_t *types;
94 } tap_data_t;
96 static const value_string part_names[] = {
97 { TYPE_VALUES, "VALUES" },
98 { TYPE_TIME, "TIME" },
99 { TYPE_TIME_HR, "TIME_HR" },
100 { TYPE_INTERVAL, "INTERVAL" },
101 { TYPE_INTERVAL_HR, "INTERVAL_HR" },
102 { TYPE_HOST, "HOST" },
103 { TYPE_PLUGIN, "PLUGIN" },
104 { TYPE_PLUGIN_INSTANCE, "PLUGIN_INSTANCE" },
105 { TYPE_TYPE, "TYPE" },
106 { TYPE_TYPE_INSTANCE, "TYPE_INSTANCE" },
107 { TYPE_MESSAGE, "MESSAGE" },
108 { TYPE_SEVERITY, "SEVERITY" },
109 { TYPE_SIGN_SHA256, "SIGNATURE" },
110 { TYPE_ENCR_AES256, "ENCRYPTED_DATA" },
111 { 0, NULL }
114 #define TYPE_VALUE_COUNTER 0x00
115 #define TYPE_VALUE_GAUGE 0x01
116 #define TYPE_VALUE_DERIVE 0x02
117 #define TYPE_VALUE_ABSOLUTE 0x03
118 static const value_string valuetypenames[] = {
119 { TYPE_VALUE_COUNTER, "COUNTER" },
120 { TYPE_VALUE_GAUGE, "GAUGE" },
121 { TYPE_VALUE_DERIVE, "DERIVE" },
122 { TYPE_VALUE_ABSOLUTE, "ABSOLUTE" },
123 { 0, NULL }
126 #define SEVERITY_FAILURE 0x01
127 #define SEVERITY_WARNING 0x02
128 #define SEVERITY_OKAY 0x04
129 static const val64_string severity_names[] = {
130 { SEVERITY_FAILURE, "FAILURE" },
131 { SEVERITY_WARNING, "WARNING" },
132 { SEVERITY_OKAY, "OKAY" },
133 { 0, NULL }
136 #define UDP_PORT_COLLECTD 25826 /* Not IANA registered */
138 static int proto_collectd;
139 static int tap_collectd = -1;
141 static int hf_collectd_type;
142 static int hf_collectd_length;
143 static int hf_collectd_data;
144 static int hf_collectd_data_host;
145 static int hf_collectd_data_time;
146 static int hf_collectd_data_interval;
147 static int hf_collectd_data_plugin;
148 static int hf_collectd_data_plugin_inst;
149 static int hf_collectd_data_type;
150 static int hf_collectd_data_type_inst;
151 static int hf_collectd_data_valcnt;
152 static int hf_collectd_val_type;
153 static int hf_collectd_val_counter;
154 static int hf_collectd_val_gauge;
155 static int hf_collectd_val_derive;
156 static int hf_collectd_val_absolute;
157 static int hf_collectd_val_unknown;
158 static int hf_collectd_data_severity;
159 static int hf_collectd_data_message;
160 static int hf_collectd_data_sighash;
161 static int hf_collectd_data_initvec;
162 static int hf_collectd_data_username_len;
163 static int hf_collectd_data_username;
164 static int hf_collectd_data_encrypted;
166 static int ett_collectd;
167 static int ett_collectd_string;
168 static int ett_collectd_integer;
169 static int ett_collectd_part_value;
170 static int ett_collectd_value;
171 static int ett_collectd_valinfo;
172 static int ett_collectd_signature;
173 static int ett_collectd_encryption;
174 static int ett_collectd_dispatch;
175 static int ett_collectd_invalid_length;
176 static int ett_collectd_unknown;
178 static int st_collectd_packets = -1;
179 static int st_collectd_values = -1;
180 static int st_collectd_values_hosts = -1;
181 static int st_collectd_values_plugins = -1;
182 static int st_collectd_values_types = -1;
184 static expert_field ei_collectd_type;
185 static expert_field ei_collectd_invalid_length;
186 static expert_field ei_collectd_data_valcnt;
187 static expert_field ei_collectd_garbage;
189 /* Prototype for the handoff function */
190 void proto_reg_handoff_collectd (void);
192 static nstime_t
193 collectd_time_to_nstime (uint64_t t)
195 nstime_t nstime = NSTIME_INIT_ZERO;
196 nstime.secs = (time_t) (t / 1073741824);
197 nstime.nsecs = (int) (((double) (t % 1073741824)) / 1.073741824);
199 return (nstime);
202 static void
203 collectd_stats_tree_init (stats_tree *st)
205 st_collectd_packets = stats_tree_create_node (st, "Packets", 0, STAT_DT_INT, false);
206 st_collectd_values = stats_tree_create_node (st, "Values", 0, STAT_DT_INT, true);
208 st_collectd_values_hosts = stats_tree_create_pivot (st, "By host",
209 st_collectd_values);
210 st_collectd_values_plugins = stats_tree_create_pivot (st, "By plugin",
211 st_collectd_values);
212 st_collectd_values_types = stats_tree_create_pivot (st, "By type",
213 st_collectd_values);
214 } /* void collectd_stats_tree_init */
216 static tap_packet_status
217 collectd_stats_tree_packet (stats_tree *st, packet_info *pinfo _U_,
218 epan_dissect_t *edt _U_, const void *user_data, tap_flags_t flags _U_)
220 const tap_data_t *td;
221 string_counter_t *sc;
223 td = (const tap_data_t *)user_data;
224 if (td == NULL)
225 return (TAP_PACKET_DONT_REDRAW);
227 tick_stat_node (st, "Packets", 0, false);
228 increase_stat_node (st, "Values", 0, true, td->values_num);
230 for (sc = td->hosts; sc != NULL; sc = sc->next)
232 int i;
233 for (i = 0; i < sc->count; i++)
234 stats_tree_tick_pivot (st, st_collectd_values_hosts,
235 sc->string);
238 for (sc = td->plugins; sc != NULL; sc = sc->next)
240 int i;
241 for (i = 0; i < sc->count; i++)
242 stats_tree_tick_pivot (st, st_collectd_values_plugins,
243 sc->string);
246 for (sc = td->types; sc != NULL; sc = sc->next)
248 int i;
249 for (i = 0; i < sc->count; i++)
250 stats_tree_tick_pivot (st, st_collectd_values_types,
251 sc->string);
254 return (TAP_PACKET_REDRAW);
255 } /* int collectd_stats_tree_packet */
257 static void
258 collectd_stats_tree_register (void)
260 stats_tree_register ("collectd", "collectd", "Collectd", 0,
261 collectd_stats_tree_packet,
262 collectd_stats_tree_init, NULL);
263 } /* void register_collectd_stat_trees */
265 static void
266 collectd_proto_tree_add_assembled_metric (tvbuff_t *tvb,
267 int offset, int length,
268 value_data_t const *vdispatch, proto_tree *root)
270 proto_item *root_item;
271 proto_tree *subtree;
272 nstime_t nstime;
274 subtree = proto_tree_add_subtree(root, tvb, offset + 6, length - 6,
275 ett_collectd_dispatch, &root_item, "Assembled metric");
276 proto_item_set_generated (root_item);
278 proto_tree_add_string (subtree, hf_collectd_data_host, tvb,
279 vdispatch->host_off, vdispatch->host_len,
280 STR_NONNULL (vdispatch->host));
282 proto_tree_add_string (subtree, hf_collectd_data_plugin, tvb,
283 vdispatch->plugin_off, vdispatch->plugin_len,
284 STR_NONNULL (vdispatch->plugin));
286 if (vdispatch->plugin_instance)
287 proto_tree_add_string (subtree,
288 hf_collectd_data_plugin_inst, tvb,
289 vdispatch->plugin_instance_off,
290 vdispatch->plugin_instance_len,
291 vdispatch->plugin_instance);
293 proto_tree_add_string (subtree, hf_collectd_data_type, tvb,
294 vdispatch->type_off, vdispatch->type_len,
295 STR_NONNULL (vdispatch->type));
297 if (vdispatch->type_instance)
298 proto_tree_add_string (subtree,
299 hf_collectd_data_type_inst, tvb,
300 vdispatch->type_instance_off,
301 vdispatch->type_instance_len,
302 vdispatch->type_instance);
304 nstime = collectd_time_to_nstime (vdispatch->time_value);
305 proto_tree_add_time (subtree, hf_collectd_data_time, tvb,
306 vdispatch->time_off, /* length = */ 8, &nstime);
308 nstime = collectd_time_to_nstime (vdispatch->interval);
309 proto_tree_add_time (subtree, hf_collectd_data_interval, tvb,
310 vdispatch->interval_off, /* length = */ 8, &nstime);
313 static void
314 collectd_proto_tree_add_assembled_notification (tvbuff_t *tvb,
315 int offset, int length,
316 notify_data_t const *ndispatch, proto_tree *root)
318 proto_item *root_item;
319 proto_tree *subtree;
320 nstime_t nstime;
322 subtree = proto_tree_add_subtree(root, tvb, offset + 6, length - 6,
323 ett_collectd_dispatch, &root_item, "Assembled notification");
324 proto_item_set_generated (root_item);
326 proto_tree_add_string (subtree, hf_collectd_data_host, tvb,
327 ndispatch->host_off, ndispatch->host_len,
328 STR_NONNULL (ndispatch->host));
330 nstime = collectd_time_to_nstime (ndispatch->time_value);
331 proto_tree_add_time (subtree, hf_collectd_data_time, tvb,
332 ndispatch->time_off, /* length = */ 8, &nstime);
334 proto_tree_add_uint64 (subtree, hf_collectd_data_severity, tvb,
335 ndispatch->severity_off, /* length = */ 8,
336 ndispatch->severity);
338 proto_tree_add_string (subtree, hf_collectd_data_message, tvb,
339 ndispatch->message_off, ndispatch->message_len,
340 ndispatch->message);
343 static int
344 dissect_collectd_string (tvbuff_t *tvb, packet_info *pinfo, int type_hf,
345 int offset, int *ret_offset, int *ret_length,
346 const uint8_t **ret_string, proto_tree *tree_root,
347 proto_item **ret_item)
349 proto_tree *pt;
350 proto_item *pi;
351 int type;
352 int length;
353 int size;
355 size = tvb_reported_length_remaining (tvb, offset);
356 if (size < 4)
358 /* This should never happen, because `dissect_collectd' checks
359 * for this condition already. */
360 return (-1);
363 type = tvb_get_ntohs(tvb, offset);
364 length = tvb_get_ntohs(tvb, offset + 2);
366 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
367 ett_collectd_string, &pi, "collectd %s segment: ",
368 val_to_str_const (type, part_names, "UNKNOWN"));
370 if (length > size)
372 proto_item_append_text(pt, "Length = %i <BAD>", length);
373 expert_add_info_format(pinfo, pt, &ei_collectd_invalid_length,
374 "String part with invalid part length: "
375 "Part is longer than rest of package.");
376 return (-1);
379 *ret_offset = offset + 4;
380 *ret_length = length - 4;
382 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
383 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
384 proto_tree_add_item_ret_string (pt, type_hf, tvb, *ret_offset, *ret_length, ENC_ASCII|ENC_NA, pinfo->pool, ret_string);
386 proto_item_append_text(pt, "\"%s\"", *ret_string);
388 if (ret_item != NULL)
389 *ret_item = pi;
391 return 0;
392 } /* int dissect_collectd_string */
394 static int
395 dissect_collectd_integer (tvbuff_t *tvb, packet_info *pinfo, int type_hf,
396 int offset, int *ret_offset, uint64_t *ret_value,
397 proto_tree *tree_root, proto_item **ret_item)
399 proto_tree *pt;
400 proto_item *pi;
401 int type;
402 int length;
403 int size;
405 size = tvb_reported_length_remaining (tvb, offset);
406 if (size < 4)
408 /* This should never happen, because `dissect_collectd' checks
409 * for this condition already. */
410 return (-1);
413 type = tvb_get_ntohs(tvb, offset);
414 length = tvb_get_ntohs(tvb, offset + 2);
416 if (size < 12)
418 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
419 ett_collectd_integer, NULL, "collectd %s segment: <BAD>",
420 val_to_str_const (type, part_names, "UNKNOWN"));
422 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2,
423 type);
424 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
425 length);
426 proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
427 "Garbage at end of packet: Length = %i <BAD>",
428 size - 4);
430 return (-1);
433 if (length != 12)
435 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
436 ett_collectd_integer, &pi, "collectd %s segment: <BAD>",
437 val_to_str_const (type, part_names, "UNKNOWN"));
439 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2,
440 type);
441 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
442 offset + 2, 2, length);
443 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
444 "Invalid length field for an integer part.");
446 return (-1);
449 *ret_offset = offset + 4;
450 *ret_value = tvb_get_ntoh64 (tvb, offset + 4);
452 /* Convert the version 4.* time format to the version 5.* time format. */
453 if ((type == TYPE_TIME) || (type == TYPE_INTERVAL))
454 *ret_value *= 1073741824;
456 /* Create an entry in the protocol tree for this part. The value is
457 * printed depending on the "type" variable: TIME{,_HR} as absolute
458 * time, INTERVAL{,_HR} as relative time, uint64 otherwise. */
459 if ((type == TYPE_TIME) || (type == TYPE_TIME_HR))
461 nstime_t nstime;
462 char *strtime;
464 nstime = collectd_time_to_nstime (*ret_value);
465 strtime = abs_time_to_str (pinfo->pool, &nstime, ABSOLUTE_TIME_LOCAL, /* show_zone = */ true);
466 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
467 ett_collectd_integer, &pi, "collectd %s segment: %s",
468 val_to_str_const (type, part_names, "UNKNOWN"),
469 STR_NONNULL (strtime));
471 else if ((type == TYPE_INTERVAL) || (type == TYPE_INTERVAL_HR))
473 nstime_t nstime;
474 char *strtime;
476 nstime = collectd_time_to_nstime (*ret_value);
477 strtime = rel_time_to_str (pinfo->pool, &nstime);
478 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
479 ett_collectd_integer, &pi, "collectd %s segment: %s",
480 val_to_str_const (type, part_names, "UNKNOWN"),
481 strtime);
483 else
485 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
486 ett_collectd_integer, &pi, "collectd %s segment: %"PRIu64,
487 val_to_str_const (type, part_names, "UNKNOWN"),
488 *ret_value);
491 if (ret_item != NULL)
492 *ret_item = pi;
494 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
495 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
496 length);
497 if ((type == TYPE_TIME) || (type == TYPE_INTERVAL)
498 || (type == TYPE_TIME_HR) || (type == TYPE_INTERVAL_HR))
500 nstime_t nstime;
502 nstime = collectd_time_to_nstime (*ret_value);
503 proto_tree_add_time (pt, type_hf, tvb, offset + 4, 8, &nstime);
505 else
507 proto_tree_add_item (pt, type_hf, tvb, offset + 4, 8, ENC_BIG_ENDIAN);
510 return 0;
511 } /* int dissect_collectd_integer */
513 static void
514 dissect_collectd_values(tvbuff_t *tvb, int msg_off, int val_cnt,
515 proto_tree *collectd_tree)
517 proto_tree *values_tree, *value_tree;
518 int i;
520 values_tree = proto_tree_add_subtree_format(collectd_tree, tvb, msg_off + 6, val_cnt * 9,
521 ett_collectd_value, NULL, "%d value%s", val_cnt,
522 plurality (val_cnt, "", "s"));
524 for (i = 0; i < val_cnt; i++)
526 int value_offset;
528 int value_type_offset;
529 uint8_t value_type;
531 /* Calculate the offsets of the type byte and the actual value. */
532 value_offset = msg_off + 6
533 + val_cnt /* value types */
534 + (i * 8); /* previous values */
536 value_type_offset = msg_off + 6 + i;
537 value_type = tvb_get_uint8 (tvb, value_type_offset);
539 switch (value_type) {
540 case TYPE_VALUE_COUNTER:
542 uint64_t val64;
544 val64 = tvb_get_ntoh64 (tvb, value_offset);
545 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
546 val_cnt * 9, ett_collectd_valinfo, NULL,
547 "Counter: %"PRIu64, val64);
549 proto_tree_add_item (value_tree, hf_collectd_val_type,
550 tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
551 proto_tree_add_item (value_tree,
552 hf_collectd_val_counter, tvb,
553 value_offset, 8, ENC_BIG_ENDIAN);
554 break;
557 case TYPE_VALUE_GAUGE:
559 double val;
561 val = tvb_get_letohieee_double (tvb, value_offset);
562 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
563 val_cnt * 9, ett_collectd_valinfo, NULL,
564 "Gauge: %g", val);
566 proto_tree_add_item (value_tree, hf_collectd_val_type,
567 tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
568 /* Set the `little endian' flag to true here, because
569 * collectd stores doubles in x86 representation. */
570 proto_tree_add_item (value_tree, hf_collectd_val_gauge,
571 tvb, value_offset, 8, ENC_LITTLE_ENDIAN);
572 break;
575 case TYPE_VALUE_DERIVE:
577 int64_t val64;
579 val64 = tvb_get_ntoh64 (tvb, value_offset);
580 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
581 val_cnt * 9, ett_collectd_valinfo, NULL,
582 "Derive: %"PRIi64, val64);
584 proto_tree_add_item (value_tree, hf_collectd_val_type,
585 tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
586 proto_tree_add_item (value_tree,
587 hf_collectd_val_derive, tvb,
588 value_offset, 8, ENC_BIG_ENDIAN);
589 break;
592 case TYPE_VALUE_ABSOLUTE:
594 uint64_t val64;
596 val64 = tvb_get_ntoh64 (tvb, value_offset);
597 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
598 val_cnt * 9, ett_collectd_valinfo, NULL,
599 "Absolute: %"PRIu64, val64);
601 proto_tree_add_item (value_tree, hf_collectd_val_type,
602 tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
603 proto_tree_add_item (value_tree,
604 hf_collectd_val_absolute, tvb,
605 value_offset, 8, ENC_BIG_ENDIAN);
606 break;
609 default:
611 uint64_t val64;
613 val64 = tvb_get_ntoh64 (tvb, value_offset);
614 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
615 val_cnt * 9, ett_collectd_valinfo, NULL,
616 "Unknown: %"PRIx64,
617 val64);
619 proto_tree_add_item (value_tree, hf_collectd_val_type,
620 tvb, value_type_offset, 1, ENC_BIG_ENDIAN);
621 proto_tree_add_item (value_tree, hf_collectd_val_unknown,
622 tvb, value_offset, 8, ENC_BIG_ENDIAN);
623 break;
625 } /* switch (value_type) */
626 } /* for (i = 0; i < val_cnt; i++) */
627 } /* void dissect_collectd_values */
629 static int
630 dissect_collectd_part_values (tvbuff_t *tvb, packet_info *pinfo, int offset,
631 value_data_t *vdispatch, proto_tree *tree_root)
633 proto_tree *pt;
634 proto_item *pi;
635 int type;
636 int length;
637 int size;
638 int values_count;
639 int corrected_values_count;
641 size = tvb_reported_length_remaining (tvb, offset);
642 if (size < 4)
644 /* This should never happen, because `dissect_collectd' checks
645 * for this condition already. */
646 return (-1);
649 type = tvb_get_ntohs (tvb, offset);
650 length = tvb_get_ntohs (tvb, offset + 2);
652 if (size < 15)
654 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
655 ett_collectd_part_value, NULL, "collectd %s segment: <BAD>",
656 val_to_str_const (type, part_names, "UNKNOWN"));
658 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
659 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
660 length);
661 proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
662 "Garbage at end of packet: Length = %i <BAD>",
663 size - 4);
664 return (-1);
667 if ((length < 15) || ((length % 9) != 6))
669 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
670 ett_collectd_part_value, &pi, "collectd %s segment: <BAD>",
671 val_to_str_const (type, part_names, "UNKNOWN"));
673 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
674 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
675 offset + 2, 2, length);
676 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
677 "Invalid length field for a values part.");
679 return (-1);
682 values_count = tvb_get_ntohs (tvb, offset + 4);
683 corrected_values_count = (length - 6) / 9;
685 if (values_count != corrected_values_count)
687 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
688 ett_collectd_part_value, NULL,
689 "collectd %s segment: %d (%d) value%s <BAD>",
690 val_to_str_const (type, part_names, "UNKNOWN"),
691 values_count, corrected_values_count,
692 plurality(values_count, "", "s"));
694 else
696 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
697 ett_collectd_part_value, NULL,
698 "collectd %s segment: %d value%s",
699 val_to_str_const (type, part_names, "UNKNOWN"),
700 values_count,
701 plurality(values_count, "", "s"));
704 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
705 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
707 pi = proto_tree_add_item (pt, hf_collectd_data_valcnt, tvb,
708 offset + 4, 2, ENC_BIG_ENDIAN);
709 if (values_count != corrected_values_count)
710 expert_add_info(pinfo, pi, &ei_collectd_data_valcnt);
712 values_count = corrected_values_count;
714 dissect_collectd_values (tvb, offset, values_count, pt);
715 collectd_proto_tree_add_assembled_metric (tvb, offset + 6, length - 6,
716 vdispatch, pt);
718 return 0;
719 } /* void dissect_collectd_part_values */
721 static int
722 dissect_collectd_signature (tvbuff_t *tvb, packet_info *pinfo,
723 int offset, proto_tree *tree_root)
725 proto_item *pi;
726 proto_tree *pt;
727 int type;
728 int length;
729 int size;
731 size = tvb_reported_length_remaining (tvb, offset);
732 if (size < 4)
734 /* This should never happen, because `dissect_collectd' checks
735 * for this condition already. */
736 return (-1);
739 type = tvb_get_ntohs (tvb, offset);
740 length = tvb_get_ntohs (tvb, offset + 2);
742 if (size < 36) /* remaining packet size too small for signature */
744 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
745 ett_collectd_signature, NULL, "collectd %s segment: <BAD>",
746 val_to_str_const (type, part_names, "UNKNOWN"));
748 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
749 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
750 length);
751 proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
752 "Garbage at end of packet: Length = %i <BAD>",
753 size - 4);
754 return (-1);
757 if (length < 36)
759 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
760 ett_collectd_signature, NULL, "collectd %s segment: <BAD>",
761 val_to_str_const (type, part_names, "UNKNOWN"));
763 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
764 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
765 offset + 2, 2, length);
766 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
767 "Invalid length field for a signature part.");
769 return (-1);
772 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
773 ett_collectd_signature, NULL, "collectd %s segment: HMAC-SHA-256",
774 val_to_str_const (type, part_names, "UNKNOWN"));
776 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
777 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
778 length);
779 proto_tree_add_item (pt, hf_collectd_data_sighash, tvb, offset + 4, 32, ENC_NA);
780 proto_tree_add_item (pt, hf_collectd_data_username, tvb, offset + 36, length - 36, ENC_ASCII);
782 return 0;
783 } /* int dissect_collectd_signature */
785 static int
786 dissect_collectd_encrypted (tvbuff_t *tvb, packet_info *pinfo,
787 int offset, proto_tree *tree_root)
789 proto_item *pi;
790 proto_tree *pt;
791 int type;
792 int length;
793 int size;
794 int username_length;
796 size = tvb_reported_length_remaining (tvb, offset);
797 if (size < 4)
799 /* This should never happen, because `dissect_collectd' checks
800 * for this condition already. */
801 return (-1);
804 type = tvb_get_ntohs (tvb, offset);
805 length = tvb_get_ntohs (tvb, offset + 2);
807 if (size < 42) /* remaining packet size too small for signature */
809 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
810 ett_collectd_encryption, NULL, "collectd %s segment: <BAD>",
811 val_to_str_const (type, part_names, "UNKNOWN"));
813 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
814 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
815 length);
816 proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
817 "Garbage at end of packet: Length = %i <BAD>",
818 size - 4);
819 return (-1);
822 if (length < 42)
824 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
825 ett_collectd_encryption, NULL, "collectd %s segment: <BAD>",
826 val_to_str_const (type, part_names, "UNKNOWN"));
828 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
829 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
830 offset + 2, 2, length);
831 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
832 "Invalid length field for an encryption part.");
834 return (-1);
837 username_length = tvb_get_ntohs (tvb, offset + 4);
838 if (username_length > (length - 42))
840 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
841 ett_collectd_encryption, NULL, "collectd %s segment: <BAD>",
842 val_to_str_const (type, part_names, "UNKNOWN"));
844 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
845 proto_tree_add_uint (pt, hf_collectd_length, tvb,
846 offset + 2, 2, length);
847 pi = proto_tree_add_uint (pt, hf_collectd_data_username_len, tvb,
848 offset + 4, 2, length);
849 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
850 "Invalid username length field for an encryption part.");
852 return (-1);
855 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
856 ett_collectd_encryption, NULL, "collectd %s segment: AES-256",
857 val_to_str_const (type, part_names, "UNKNOWN"));
859 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
860 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
861 proto_tree_add_uint (pt, hf_collectd_data_username_len, tvb, offset + 4, 2, username_length);
862 proto_tree_add_item (pt, hf_collectd_data_username, tvb, offset + 6, username_length, ENC_ASCII);
863 proto_tree_add_item (pt, hf_collectd_data_initvec, tvb,
864 offset + (6 + username_length), 16, ENC_NA);
865 proto_tree_add_item (pt, hf_collectd_data_encrypted, tvb,
866 offset + (22 + username_length),
867 length - (22 + username_length), ENC_NA);
869 return 0;
870 } /* int dissect_collectd_encrypted */
872 static int
873 stats_account_string (wmem_allocator_t *scope, string_counter_t **ret_list, const char *new_value)
875 string_counter_t *entry;
877 if (ret_list == NULL)
878 return (-1);
880 if (new_value == NULL)
881 new_value = "(null)";
883 for (entry = *ret_list; entry != NULL; entry = entry->next)
884 if (strcmp (new_value, entry->string) == 0)
886 entry->count++;
887 return 0;
890 entry = (string_counter_t *)wmem_alloc0 (scope, sizeof (*entry));
891 entry->string = wmem_strdup (scope, new_value);
892 entry->count = 1;
893 entry->next = *ret_list;
895 *ret_list = entry;
897 return 0;
900 static int
901 dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
903 static tap_data_t tap_data;
905 int offset;
906 int size;
907 const uint8_t *pkt_host = NULL;
908 int pkt_plugins = 0, pkt_values = 0, pkt_messages = 0, pkt_unknown = 0, pkt_errors = 0;
909 value_data_t vdispatch;
910 notify_data_t ndispatch;
911 int status;
912 proto_item *pi;
913 proto_tree *collectd_tree;
914 proto_tree *pt;
916 memset(&vdispatch, '\0', sizeof(vdispatch));
917 memset(&ndispatch, '\0', sizeof(ndispatch));
919 col_set_str(pinfo->cinfo, COL_PROTOCOL, "collectd");
920 col_clear(pinfo->cinfo, COL_INFO);
922 offset = 0;
923 size = tvb_reported_length(tvb);
925 /* create the collectd protocol tree */
926 pi = proto_tree_add_item(tree, proto_collectd, tvb, 0, -1, ENC_NA);
927 collectd_tree = proto_item_add_subtree(pi, ett_collectd);
929 memset (&tap_data, 0, sizeof (tap_data));
931 status = 0;
932 while ((size > 0) && (status == 0))
935 int part_type;
936 int part_length;
938 /* Let's handle the easy case first real quick: All we do here
939 * is extract a host name and count the number of values,
940 * plugins and notifications. The payload is not checked at
941 * all, but the same checks are run on the part_length stuff -
942 * it's important to keep an eye on that. */
943 if (!tree)
945 /* Check for garbage at end of packet. */
946 if (size < 4)
948 pkt_errors++;
949 break;
952 part_type = tvb_get_ntohs (tvb, offset);
953 part_length = tvb_get_ntohs (tvb, offset+2);
955 /* Check if part_length is in the valid range. */
956 if ((part_length < 4) || (part_length > size))
958 pkt_errors++;
959 break;
962 switch (part_type) {
963 case TYPE_HOST:
964 vdispatch.host = tvb_get_string_enc(pinfo->pool, tvb,
965 offset + 4, part_length - 4, ENC_ASCII);
966 if (pkt_host == NULL)
967 pkt_host = vdispatch.host;
968 break;
969 case TYPE_TIME:
970 case TYPE_TIME_HR:
971 break;
972 case TYPE_PLUGIN:
973 vdispatch.plugin = tvb_get_string_enc(pinfo->pool, tvb,
974 offset + 4, part_length - 4, ENC_ASCII);
975 pkt_plugins++;
976 break;
977 case TYPE_PLUGIN_INSTANCE:
978 break;
979 case TYPE_TYPE:
980 vdispatch.type = tvb_get_string_enc(pinfo->pool, tvb,
981 offset + 4, part_length - 4, ENC_ASCII);
982 break;
983 case TYPE_TYPE_INSTANCE:
984 break;
985 case TYPE_INTERVAL:
986 case TYPE_INTERVAL_HR:
987 break;
988 case TYPE_VALUES:
990 pkt_values++;
992 tap_data.values_num++;
993 stats_account_string (pinfo->pool,
994 &tap_data.hosts,
995 vdispatch.host);
996 stats_account_string (pinfo->pool,
997 &tap_data.plugins,
998 vdispatch.plugin);
999 stats_account_string (pinfo->pool,
1000 &tap_data.types,
1001 vdispatch.type);
1003 break;
1005 case TYPE_MESSAGE:
1006 pkt_messages++;
1007 break;
1008 case TYPE_SEVERITY:
1009 break;
1010 default:
1011 pkt_unknown++;
1014 offset += part_length;
1015 size -= part_length;
1016 continue;
1017 } /* if (!tree) */
1019 /* Now we do the same steps again, but much more thoroughly. */
1021 /* Check if there are at least four bytes left first.
1022 * Four bytes are used to read the type and the length
1023 * of the next part. If there's less, there's some garbage
1024 * at the end of the packet. */
1025 if (size < 4)
1027 proto_tree_add_expert_format(pi, pinfo, &ei_collectd_garbage, tvb,
1028 offset, -1,
1029 "Garbage at end of packet: Length = %i <BAD>",
1030 size);
1031 pkt_errors++;
1032 break;
1035 /* dissect a message entry */
1036 part_type = tvb_get_ntohs (tvb, offset);
1037 part_length = tvb_get_ntohs (tvb, offset + 2);
1039 /* Check if the length of the part is in the valid range. Don't
1040 * confuse this with the above: Here we check the information
1041 * provided in the packet.. */
1042 if ((part_length < 4) || (part_length > size))
1044 pt = proto_tree_add_subtree_format(collectd_tree, tvb,
1045 offset, part_length, ett_collectd_invalid_length, NULL,
1046 "collectd %s segment: Length = %i <BAD>",
1047 val_to_str_const (part_type, part_names, "UNKNOWN"),
1048 part_length);
1050 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset,
1051 2, part_type);
1052 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
1053 offset + 2, 2, part_length);
1055 if (part_length < 4)
1056 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
1057 "Bad part length: Is %i, expected at least 4",
1058 part_length);
1059 else
1060 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
1061 "Bad part length: Larger than remaining packet size.");
1063 pkt_errors++;
1064 break;
1067 /* The header information looks okay, let's tend to the actual
1068 * payload in this part. */
1069 switch (part_type) {
1070 case TYPE_HOST:
1072 status = dissect_collectd_string (tvb, pinfo,
1073 hf_collectd_data_host,
1074 offset,
1075 &vdispatch.host_off,
1076 &vdispatch.host_len,
1077 &vdispatch.host,
1078 collectd_tree, /* item = */ NULL);
1079 if (status != 0)
1080 pkt_errors++;
1081 else
1083 if (pkt_host == NULL)
1084 pkt_host = vdispatch.host;
1085 ndispatch.host_off = vdispatch.host_off;
1086 ndispatch.host_len = vdispatch.host_len;
1087 ndispatch.host = vdispatch.host;
1090 break;
1093 case TYPE_PLUGIN:
1095 status = dissect_collectd_string (tvb, pinfo,
1096 hf_collectd_data_plugin,
1097 offset,
1098 &vdispatch.plugin_off,
1099 &vdispatch.plugin_len,
1100 &vdispatch.plugin,
1101 collectd_tree, /* item = */ NULL);
1102 if (status != 0)
1103 pkt_errors++;
1104 else
1105 pkt_plugins++;
1107 break;
1110 case TYPE_PLUGIN_INSTANCE:
1112 status = dissect_collectd_string (tvb, pinfo,
1113 hf_collectd_data_plugin_inst,
1114 offset,
1115 &vdispatch.plugin_instance_off,
1116 &vdispatch.plugin_instance_len,
1117 &vdispatch.plugin_instance,
1118 collectd_tree, /* item = */ NULL);
1119 if (status != 0)
1120 pkt_errors++;
1122 break;
1125 case TYPE_TYPE:
1127 status = dissect_collectd_string (tvb, pinfo,
1128 hf_collectd_data_type,
1129 offset,
1130 &vdispatch.type_off,
1131 &vdispatch.type_len,
1132 &vdispatch.type,
1133 collectd_tree, /* item = */ NULL);
1134 if (status != 0)
1135 pkt_errors++;
1137 break;
1140 case TYPE_TYPE_INSTANCE:
1142 status = dissect_collectd_string (tvb, pinfo,
1143 hf_collectd_data_type_inst,
1144 offset,
1145 &vdispatch.type_instance_off,
1146 &vdispatch.type_instance_len,
1147 &vdispatch.type_instance,
1148 collectd_tree, /* item = */ NULL);
1149 if (status != 0)
1150 pkt_errors++;
1152 break;
1155 case TYPE_TIME:
1156 case TYPE_TIME_HR:
1158 pi = NULL;
1159 status = dissect_collectd_integer (tvb, pinfo,
1160 hf_collectd_data_time,
1161 offset,
1162 &vdispatch.time_off,
1163 &vdispatch.time_value,
1164 collectd_tree, &pi);
1165 if (status != 0)
1166 pkt_errors++;
1168 break;
1171 case TYPE_INTERVAL:
1172 case TYPE_INTERVAL_HR:
1174 status = dissect_collectd_integer (tvb, pinfo,
1175 hf_collectd_data_interval,
1176 offset,
1177 &vdispatch.interval_off,
1178 &vdispatch.interval,
1179 collectd_tree, /* item = */ NULL);
1180 if (status != 0)
1181 pkt_errors++;
1183 break;
1186 case TYPE_VALUES:
1188 status = dissect_collectd_part_values (tvb, pinfo,
1189 offset,
1190 &vdispatch,
1191 collectd_tree);
1192 if (status != 0)
1193 pkt_errors++;
1194 else
1195 pkt_values++;
1197 tap_data.values_num++;
1198 stats_account_string (pinfo->pool,
1199 &tap_data.hosts,
1200 vdispatch.host);
1201 stats_account_string (pinfo->pool,
1202 &tap_data.plugins,
1203 vdispatch.plugin);
1204 stats_account_string (pinfo->pool,
1205 &tap_data.types,
1206 vdispatch.type);
1208 break;
1211 case TYPE_MESSAGE:
1213 pi = NULL;
1214 status = dissect_collectd_string (tvb, pinfo,
1215 hf_collectd_data_message,
1216 offset,
1217 &ndispatch.message_off,
1218 &ndispatch.message_len,
1219 &ndispatch.message,
1220 collectd_tree, &pi);
1221 if (status != 0)
1223 pkt_errors++;
1224 break;
1226 pkt_messages++;
1228 pt = proto_item_get_subtree (pi);
1230 collectd_proto_tree_add_assembled_notification (tvb,
1231 offset + 4, part_length - 1,
1232 &ndispatch, pt);
1234 break;
1237 case TYPE_SEVERITY:
1239 pi = NULL;
1240 status = dissect_collectd_integer (tvb, pinfo,
1241 hf_collectd_data_severity,
1242 offset,
1243 &ndispatch.severity_off,
1244 &ndispatch.severity,
1245 collectd_tree, &pi);
1246 if (status != 0)
1247 pkt_errors++;
1248 else
1250 proto_item_set_text (pi,
1251 "collectd SEVERITY segment: "
1252 "%s (%"PRIu64")",
1253 val64_to_str_const (ndispatch.severity, severity_names, "UNKNOWN"),
1254 ndispatch.severity);
1257 break;
1260 case TYPE_SIGN_SHA256:
1262 status = dissect_collectd_signature (tvb, pinfo,
1263 offset,
1264 collectd_tree);
1265 if (status != 0)
1266 pkt_errors++;
1268 break;
1271 case TYPE_ENCR_AES256:
1273 status = dissect_collectd_encrypted (tvb, pinfo,
1274 offset, collectd_tree);
1275 if (status != 0)
1276 pkt_errors++;
1278 break;
1281 default:
1283 pkt_unknown++;
1284 pt = proto_tree_add_subtree_format(collectd_tree, tvb,
1285 offset, part_length, ett_collectd_unknown, NULL,
1286 "collectd %s segment: %i bytes",
1287 val_to_str_const(part_type, part_names, "UNKNOWN"),
1288 part_length);
1290 pi = proto_tree_add_uint (pt, hf_collectd_type, tvb,
1291 offset, 2, part_type);
1292 proto_tree_add_uint (pt, hf_collectd_length, tvb,
1293 offset + 2, 2, part_length);
1294 proto_tree_add_item (pt, hf_collectd_data, tvb,
1295 offset + 4, part_length - 4, ENC_NA);
1297 expert_add_info_format(pinfo, pi, &ei_collectd_type,
1298 "Unknown part type %#x. Cannot decode data.",
1299 part_type);
1301 } /* switch (part_type) */
1303 offset += part_length;
1304 size -= part_length;
1305 } /* while ((size > 4) && (status == 0)) */
1307 if (pkt_errors && pkt_unknown)
1308 col_add_fstr (pinfo->cinfo, COL_INFO,
1309 "Host=%s, %2d value%s for %d plugin%s %d message%s %d unknown, %d error%s",
1310 pkt_host,
1311 pkt_values, plurality (pkt_values, " ", "s"),
1312 pkt_plugins, plurality (pkt_plugins, ", ", "s,"),
1313 pkt_messages, plurality (pkt_messages, ", ", "s,"),
1314 pkt_unknown,
1315 pkt_errors, plurality (pkt_errors, "", "s"));
1316 else if (pkt_errors)
1317 col_add_fstr (pinfo->cinfo, COL_INFO, "Host=%s, %2d value%s for %d plugin%s %d message%s %d error%s",
1318 pkt_host,
1319 pkt_values, plurality (pkt_values, " ", "s"),
1320 pkt_plugins, plurality (pkt_plugins, ", ", "s,"),
1321 pkt_messages, plurality (pkt_messages, ", ", "s,"),
1322 pkt_errors, plurality (pkt_errors, "", "s"));
1323 else if (pkt_unknown)
1324 col_add_fstr (pinfo->cinfo, COL_INFO,
1325 "Host=%s, %2d value%s for %d plugin%s %d message%s %d unknown",
1326 pkt_host,
1327 pkt_values, plurality (pkt_values, " ", "s"),
1328 pkt_plugins, plurality (pkt_plugins, ", ", "s,"),
1329 pkt_messages, plurality (pkt_messages, ", ", "s,"),
1330 pkt_unknown);
1331 else
1332 col_add_fstr (pinfo->cinfo, COL_INFO, "Host=%s, %2d value%s for %d plugin%s %d message%s",
1333 pkt_host,
1334 pkt_values, plurality (pkt_values, " ", "s"),
1335 pkt_plugins, plurality (pkt_plugins, ", ", "s,"),
1336 pkt_messages, plurality (pkt_messages, "", "s"));
1338 /* Dispatch tap data. */
1339 tap_queue_packet (tap_collectd, pinfo, &tap_data);
1340 return tvb_captured_length(tvb);
1341 } /* void dissect_collectd */
1343 void proto_register_collectd(void)
1345 expert_module_t* expert_collectd;
1347 /* Setup list of header fields */
1348 static hf_register_info hf[] = {
1349 { &hf_collectd_type,
1350 { "Type", "collectd.type", FT_UINT16, BASE_HEX,
1351 VALS(part_names), 0x0, NULL, HFILL }
1353 { &hf_collectd_length,
1354 { "Length", "collectd.len", FT_UINT16, BASE_DEC,
1355 NULL, 0x0, NULL, HFILL }
1357 { &hf_collectd_data,
1358 { "Payload", "collectd.data", FT_BYTES, BASE_NONE,
1359 NULL, 0x0, NULL, HFILL }
1361 { &hf_collectd_data_host,
1362 { "Host name", "collectd.data.host", FT_STRING, BASE_NONE,
1363 NULL, 0x0, NULL, HFILL }
1365 { &hf_collectd_data_interval,
1366 { "Interval", "collectd.data.interval", FT_RELATIVE_TIME, BASE_NONE,
1367 NULL, 0x0, NULL, HFILL }
1369 { &hf_collectd_data_time,
1370 { "Timestamp", "collectd.data.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1371 NULL, 0x0, NULL, HFILL }
1373 { &hf_collectd_data_plugin,
1374 { "Plugin", "collectd.data.plugin", FT_STRING, BASE_NONE,
1375 NULL, 0x0, NULL, HFILL }
1377 { &hf_collectd_data_plugin_inst,
1378 { "Plugin instance", "collectd.data.plugin.inst", FT_STRING, BASE_NONE,
1379 NULL, 0x0, NULL, HFILL }
1381 { &hf_collectd_data_type,
1382 { "Type", "collectd.data.type", FT_STRING, BASE_NONE,
1383 NULL, 0x0, NULL, HFILL }
1385 { &hf_collectd_data_type_inst,
1386 { "Type instance", "collectd.data.type.inst", FT_STRING, BASE_NONE,
1387 NULL, 0x0, NULL, HFILL }
1389 { &hf_collectd_data_valcnt,
1390 { "Value count", "collectd.data.valcnt", FT_UINT16, BASE_DEC,
1391 NULL, 0x0, NULL, HFILL }
1393 { &hf_collectd_val_type,
1394 { "Value type", "collectd.val.type", FT_UINT8, BASE_HEX,
1395 VALS(valuetypenames), 0x0, NULL, HFILL }
1397 { &hf_collectd_val_counter,
1398 { "Counter value", "collectd.val.counter", FT_UINT64, BASE_DEC,
1399 NULL, 0x0, NULL, HFILL }
1401 { &hf_collectd_val_gauge,
1402 { "Gauge value", "collectd.val.gauge", FT_DOUBLE, BASE_NONE,
1403 NULL, 0x0, NULL, HFILL }
1405 { &hf_collectd_val_derive,
1406 { "Derive value", "collectd.val.derive", FT_INT64, BASE_DEC,
1407 NULL, 0x0, NULL, HFILL }
1409 { &hf_collectd_val_absolute,
1410 { "Absolute value", "collectd.val.absolute", FT_UINT64, BASE_DEC,
1411 NULL, 0x0, NULL, HFILL }
1413 { &hf_collectd_val_unknown,
1414 { "Value of unknown type", "collectd.val.unknown", FT_UINT64, BASE_HEX,
1415 NULL, 0x0, NULL, HFILL }
1417 { &hf_collectd_data_severity,
1418 { "Severity", "collectd.data.severity", FT_UINT64, BASE_HEX | BASE_VAL64_STRING,
1419 VALS64(severity_names),
1420 0x0, NULL, HFILL }
1422 { &hf_collectd_data_message,
1423 { "Message", "collectd.data.message", FT_STRING, BASE_NONE,
1424 NULL, 0x0, NULL, HFILL }
1426 { &hf_collectd_data_sighash,
1427 { "Signature", "collectd.data.sighash", FT_BYTES, BASE_NONE,
1428 NULL, 0x0, NULL, HFILL }
1430 { &hf_collectd_data_initvec,
1431 { "Init vector", "collectd.data.initvec", FT_BYTES, BASE_NONE,
1432 NULL, 0x0, NULL, HFILL }
1434 { &hf_collectd_data_username_len,
1435 { "Username length", "collectd.data.username_length", FT_UINT16, BASE_DEC,
1436 NULL, 0x0, NULL, HFILL }
1438 { &hf_collectd_data_username,
1439 { "Username", "collectd.data.username", FT_STRING, BASE_NONE,
1440 NULL, 0x0, NULL, HFILL }
1442 { &hf_collectd_data_encrypted,
1443 { "Encrypted data", "collectd.data.encrypted", FT_BYTES, BASE_NONE,
1444 NULL, 0x0, NULL, HFILL }
1448 /* Setup protocol subtree array */
1449 static int *ett[] = {
1450 &ett_collectd,
1451 &ett_collectd_string,
1452 &ett_collectd_integer,
1453 &ett_collectd_part_value,
1454 &ett_collectd_value,
1455 &ett_collectd_valinfo,
1456 &ett_collectd_signature,
1457 &ett_collectd_encryption,
1458 &ett_collectd_dispatch,
1459 &ett_collectd_invalid_length,
1460 &ett_collectd_unknown,
1463 static ei_register_info ei[] = {
1464 { &ei_collectd_invalid_length, { "collectd.invalid_length", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
1465 { &ei_collectd_garbage, { "collectd.garbage", PI_MALFORMED, PI_ERROR, "Garbage at end of packet", EXPFILL }},
1466 { &ei_collectd_data_valcnt, { "collectd.data.valcnt.mismatch", PI_MALFORMED, PI_WARN, "Number of values and length of part do not match. Assuming length is correct.", EXPFILL }},
1467 { &ei_collectd_type, { "collectd.type.unknown", PI_UNDECODED, PI_NOTE, "Unknown part type", EXPFILL }},
1470 /* Register the protocol name and description */
1471 proto_collectd = proto_register_protocol("collectd network data", "collectd", "collectd");
1473 /* Required function calls to register the header fields and subtrees used */
1474 proto_register_field_array(proto_collectd, hf, array_length(hf));
1475 proto_register_subtree_array(ett, array_length(ett));
1476 expert_collectd = expert_register_protocol(proto_collectd);
1477 expert_register_field_array(expert_collectd, ei, array_length(ei));
1479 tap_collectd = register_tap ("collectd");
1481 collectd_handle = register_dissector("collectd", dissect_collectd, proto_collectd);
1484 void proto_reg_handoff_collectd (void)
1486 dissector_add_uint_with_preference("udp.port", UDP_PORT_COLLECTD, collectd_handle);
1488 collectd_stats_tree_register ();
1489 } /* void proto_reg_handoff_collectd */
1492 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1494 * Local variables:
1495 * c-basic-offset: 8
1496 * tab-width: 8
1497 * indent-tabs-mode: t
1498 * End:
1500 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1501 * :indentSize=8:tabSize=8:noTabs=false: