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
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
{
52 const uint8_t *plugin
;
55 const uint8_t *plugin_instance
;
56 int plugin_instance_off
;
57 int plugin_instance_len
;
61 const uint8_t *type_instance
;
62 int type_instance_off
;
63 int type_instance_len
;
66 typedef struct notify_data_s
{
74 const uint8_t *message
;
79 struct string_counter_s
;
80 typedef struct string_counter_s string_counter_t
;
81 struct string_counter_s
85 string_counter_t
*next
;
88 typedef struct tap_data_s
{
91 string_counter_t
*hosts
;
92 string_counter_t
*plugins
;
93 string_counter_t
*types
;
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" },
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" },
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" },
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);
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);
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",
210 st_collectd_values_plugins
= stats_tree_create_pivot (st
, "By plugin",
212 st_collectd_values_types
= stats_tree_create_pivot (st
, "By type",
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
;
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
)
233 for (i
= 0; i
< sc
->count
; i
++)
234 stats_tree_tick_pivot (st
, st_collectd_values_hosts
,
238 for (sc
= td
->plugins
; sc
!= NULL
; sc
= sc
->next
)
241 for (i
= 0; i
< sc
->count
; i
++)
242 stats_tree_tick_pivot (st
, st_collectd_values_plugins
,
246 for (sc
= td
->types
; sc
!= NULL
; sc
= sc
->next
)
249 for (i
= 0; i
< sc
->count
; i
++)
250 stats_tree_tick_pivot (st
, st_collectd_values_types
,
254 return (TAP_PACKET_REDRAW
);
255 } /* int collectd_stats_tree_packet */
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 */
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
;
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
);
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
;
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
,
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
)
355 size
= tvb_reported_length_remaining (tvb
, offset
);
358 /* This should never happen, because `dissect_collectd' checks
359 * for this condition already. */
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"));
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.");
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
)
392 } /* int dissect_collectd_string */
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
)
405 size
= tvb_reported_length_remaining (tvb
, offset
);
408 /* This should never happen, because `dissect_collectd' checks
409 * for this condition already. */
413 type
= tvb_get_ntohs(tvb
, offset
);
414 length
= tvb_get_ntohs(tvb
, offset
+ 2);
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,
424 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2,
426 proto_tree_add_expert_format(pt
, pinfo
, &ei_collectd_garbage
, tvb
, offset
+ 4, -1,
427 "Garbage at end of packet: Length = %i <BAD>",
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,
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.");
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
))
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
))
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"),
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"),
491 if (ret_item
!= NULL
)
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,
497 if ((type
== TYPE_TIME
) || (type
== TYPE_INTERVAL
)
498 || (type
== TYPE_TIME_HR
) || (type
== TYPE_INTERVAL_HR
))
502 nstime
= collectd_time_to_nstime (*ret_value
);
503 proto_tree_add_time (pt
, type_hf
, tvb
, offset
+ 4, 8, &nstime
);
507 proto_tree_add_item (pt
, type_hf
, tvb
, offset
+ 4, 8, ENC_BIG_ENDIAN
);
511 } /* int dissect_collectd_integer */
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
;
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
++)
528 int value_type_offset
;
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
:
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
);
557 case TYPE_VALUE_GAUGE
:
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
,
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
);
575 case TYPE_VALUE_DERIVE
:
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
);
592 case TYPE_VALUE_ABSOLUTE
:
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
);
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
,
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
);
625 } /* switch (value_type) */
626 } /* for (i = 0; i < val_cnt; i++) */
627 } /* void dissect_collectd_values */
630 dissect_collectd_part_values (tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
,
631 value_data_t
*vdispatch
, proto_tree
*tree_root
)
639 int corrected_values_count
;
641 size
= tvb_reported_length_remaining (tvb
, offset
);
644 /* This should never happen, because `dissect_collectd' checks
645 * for this condition already. */
649 type
= tvb_get_ntohs (tvb
, offset
);
650 length
= tvb_get_ntohs (tvb
, offset
+ 2);
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,
661 proto_tree_add_expert_format(pt
, pinfo
, &ei_collectd_garbage
, tvb
, offset
+ 4, -1,
662 "Garbage at end of packet: Length = %i <BAD>",
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.");
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"));
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"),
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,
719 } /* void dissect_collectd_part_values */
722 dissect_collectd_signature (tvbuff_t
*tvb
, packet_info
*pinfo
,
723 int offset
, proto_tree
*tree_root
)
731 size
= tvb_reported_length_remaining (tvb
, offset
);
734 /* This should never happen, because `dissect_collectd' checks
735 * for this condition already. */
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,
751 proto_tree_add_expert_format(pt
, pinfo
, &ei_collectd_garbage
, tvb
, offset
+ 4, -1,
752 "Garbage at end of packet: Length = %i <BAD>",
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.");
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,
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
);
783 } /* int dissect_collectd_signature */
786 dissect_collectd_encrypted (tvbuff_t
*tvb
, packet_info
*pinfo
,
787 int offset
, proto_tree
*tree_root
)
796 size
= tvb_reported_length_remaining (tvb
, offset
);
799 /* This should never happen, because `dissect_collectd' checks
800 * for this condition already. */
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,
816 proto_tree_add_expert_format(pt
, pinfo
, &ei_collectd_garbage
, tvb
, offset
+ 4, -1,
817 "Garbage at end of packet: Length = %i <BAD>",
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.");
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.");
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
);
870 } /* int dissect_collectd_encrypted */
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
)
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)
890 entry
= (string_counter_t
*)wmem_alloc0 (scope
, sizeof (*entry
));
891 entry
->string
= wmem_strdup (scope
, new_value
);
893 entry
->next
= *ret_list
;
901 dissect_collectd (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
903 static tap_data_t tap_data
;
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
;
913 proto_tree
*collectd_tree
;
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
);
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
));
932 while ((size
> 0) && (status
== 0))
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. */
945 /* Check for garbage at end of packet. */
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
))
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
;
973 vdispatch
.plugin
= tvb_get_string_enc(pinfo
->pool
, tvb
,
974 offset
+ 4, part_length
- 4, ENC_ASCII
);
977 case TYPE_PLUGIN_INSTANCE
:
980 vdispatch
.type
= tvb_get_string_enc(pinfo
->pool
, tvb
,
981 offset
+ 4, part_length
- 4, ENC_ASCII
);
983 case TYPE_TYPE_INSTANCE
:
986 case TYPE_INTERVAL_HR
:
992 tap_data
.values_num
++;
993 stats_account_string (pinfo
->pool
,
996 stats_account_string (pinfo
->pool
,
999 stats_account_string (pinfo
->pool
,
1014 offset
+= part_length
;
1015 size
-= part_length
;
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. */
1027 proto_tree_add_expert_format(pi
, pinfo
, &ei_collectd_garbage
, tvb
,
1029 "Garbage at end of packet: Length = %i <BAD>",
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"),
1050 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
,
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",
1060 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
1061 "Bad part length: Larger than remaining packet size.");
1067 /* The header information looks okay, let's tend to the actual
1068 * payload in this part. */
1069 switch (part_type
) {
1072 status
= dissect_collectd_string (tvb
, pinfo
,
1073 hf_collectd_data_host
,
1075 &vdispatch
.host_off
,
1076 &vdispatch
.host_len
,
1078 collectd_tree
, /* item = */ NULL
);
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
;
1095 status
= dissect_collectd_string (tvb
, pinfo
,
1096 hf_collectd_data_plugin
,
1098 &vdispatch
.plugin_off
,
1099 &vdispatch
.plugin_len
,
1101 collectd_tree
, /* item = */ NULL
);
1110 case TYPE_PLUGIN_INSTANCE
:
1112 status
= dissect_collectd_string (tvb
, pinfo
,
1113 hf_collectd_data_plugin_inst
,
1115 &vdispatch
.plugin_instance_off
,
1116 &vdispatch
.plugin_instance_len
,
1117 &vdispatch
.plugin_instance
,
1118 collectd_tree
, /* item = */ NULL
);
1127 status
= dissect_collectd_string (tvb
, pinfo
,
1128 hf_collectd_data_type
,
1130 &vdispatch
.type_off
,
1131 &vdispatch
.type_len
,
1133 collectd_tree
, /* item = */ NULL
);
1140 case TYPE_TYPE_INSTANCE
:
1142 status
= dissect_collectd_string (tvb
, pinfo
,
1143 hf_collectd_data_type_inst
,
1145 &vdispatch
.type_instance_off
,
1146 &vdispatch
.type_instance_len
,
1147 &vdispatch
.type_instance
,
1148 collectd_tree
, /* item = */ NULL
);
1159 status
= dissect_collectd_integer (tvb
, pinfo
,
1160 hf_collectd_data_time
,
1162 &vdispatch
.time_off
,
1163 &vdispatch
.time_value
,
1164 collectd_tree
, &pi
);
1172 case TYPE_INTERVAL_HR
:
1174 status
= dissect_collectd_integer (tvb
, pinfo
,
1175 hf_collectd_data_interval
,
1177 &vdispatch
.interval_off
,
1178 &vdispatch
.interval
,
1179 collectd_tree
, /* item = */ NULL
);
1188 status
= dissect_collectd_part_values (tvb
, pinfo
,
1197 tap_data
.values_num
++;
1198 stats_account_string (pinfo
->pool
,
1201 stats_account_string (pinfo
->pool
,
1204 stats_account_string (pinfo
->pool
,
1214 status
= dissect_collectd_string (tvb
, pinfo
,
1215 hf_collectd_data_message
,
1217 &ndispatch
.message_off
,
1218 &ndispatch
.message_len
,
1220 collectd_tree
, &pi
);
1228 pt
= proto_item_get_subtree (pi
);
1230 collectd_proto_tree_add_assembled_notification (tvb
,
1231 offset
+ 4, part_length
- 1,
1240 status
= dissect_collectd_integer (tvb
, pinfo
,
1241 hf_collectd_data_severity
,
1243 &ndispatch
.severity_off
,
1244 &ndispatch
.severity
,
1245 collectd_tree
, &pi
);
1250 proto_item_set_text (pi
,
1251 "collectd SEVERITY segment: "
1253 val64_to_str_const (ndispatch
.severity
, severity_names
, "UNKNOWN"),
1254 ndispatch
.severity
);
1260 case TYPE_SIGN_SHA256
:
1262 status
= dissect_collectd_signature (tvb
, pinfo
,
1271 case TYPE_ENCR_AES256
:
1273 status
= dissect_collectd_encrypted (tvb
, pinfo
,
1274 offset
, collectd_tree
);
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"),
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.",
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",
1311 pkt_values
, plurality (pkt_values
, " ", "s"),
1312 pkt_plugins
, plurality (pkt_plugins
, ", ", "s,"),
1313 pkt_messages
, plurality (pkt_messages
, ", ", "s,"),
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",
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",
1327 pkt_values
, plurality (pkt_values
, " ", "s"),
1328 pkt_plugins
, plurality (pkt_plugins
, ", ", "s,"),
1329 pkt_messages
, plurality (pkt_messages
, ", ", "s,"),
1332 col_add_fstr (pinfo
->cinfo
, COL_INFO
, "Host=%s, %2d value%s for %d plugin%s %d message%s",
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
),
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
[] = {
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
1497 * indent-tabs-mode: t
1500 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1501 * :indentSize=8:tabSize=8:noTabs=false: