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>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include <epan/packet.h>
33 #include <epan/prefs.h>
34 #include <epan/expert.h>
35 #include <epan/stats_tree.h>
36 #include <epan/wmem/wmem.h>
38 #define STR_NONNULL(str) ((str) ? (str) : "(null)")
40 #define TYPE_HOST 0x0000
41 #define TYPE_TIME 0x0001
42 #define TYPE_TIME_HR 0x0008
43 #define TYPE_PLUGIN 0x0002
44 #define TYPE_PLUGIN_INSTANCE 0x0003
45 #define TYPE_TYPE 0x0004
46 #define TYPE_TYPE_INSTANCE 0x0005
47 #define TYPE_VALUES 0x0006
48 #define TYPE_INTERVAL 0x0007
49 #define TYPE_INTERVAL_HR 0x0009
50 #define TYPE_MESSAGE 0x0100
51 #define TYPE_SEVERITY 0x0101
52 #define TYPE_SIGN_SHA256 0x0200
53 #define TYPE_ENCR_AES256 0x0210
55 void proto_register_collectd(void);
57 typedef struct value_data_s
{
68 gchar
*plugin_instance
;
69 gint plugin_instance_off
;
70 gint plugin_instance_len
;
75 gint type_instance_off
;
76 gint type_instance_len
;
79 typedef struct notify_data_s
{
92 struct string_counter_s
;
93 typedef struct string_counter_s string_counter_t
;
94 struct string_counter_s
98 string_counter_t
*next
;
101 typedef struct tap_data_s
{
104 string_counter_t
*hosts
;
105 string_counter_t
*plugins
;
106 string_counter_t
*types
;
109 static const value_string part_names
[] = {
110 { TYPE_VALUES
, "VALUES" },
111 { TYPE_TIME
, "TIME" },
112 { TYPE_TIME_HR
, "TIME_HR" },
113 { TYPE_INTERVAL
, "INTERVAL" },
114 { TYPE_INTERVAL_HR
, "INTERVAL_HR" },
115 { TYPE_HOST
, "HOST" },
116 { TYPE_PLUGIN
, "PLUGIN" },
117 { TYPE_PLUGIN_INSTANCE
, "PLUGIN_INSTANCE" },
118 { TYPE_TYPE
, "TYPE" },
119 { TYPE_TYPE_INSTANCE
, "TYPE_INSTANCE" },
120 { TYPE_MESSAGE
, "MESSAGE" },
121 { TYPE_SEVERITY
, "SEVERITY" },
122 { TYPE_SIGN_SHA256
, "SIGNATURE" },
123 { TYPE_ENCR_AES256
, "ENCRYPTED_DATA" },
127 #define TYPE_VALUE_COUNTER 0x00
128 #define TYPE_VALUE_GAUGE 0x01
129 #define TYPE_VALUE_DERIVE 0x02
130 #define TYPE_VALUE_ABSOLUTE 0x03
131 static const value_string valuetypenames
[] = {
132 { TYPE_VALUE_COUNTER
, "COUNTER" },
133 { TYPE_VALUE_GAUGE
, "GAUGE" },
134 { TYPE_VALUE_DERIVE
, "DERIVE" },
135 { TYPE_VALUE_ABSOLUTE
, "ABSOLUTE" },
139 #define SEVERITY_FAILURE 0x01
140 #define SEVERITY_WARNING 0x02
141 #define SEVERITY_OKAY 0x04
142 static const val64_string severity_names
[] = {
143 { SEVERITY_FAILURE
, "FAILURE" },
144 { SEVERITY_WARNING
, "WARNING" },
145 { SEVERITY_OKAY
, "OKAY" },
149 #define UDP_PORT_COLLECTD 25826
150 static guint collectd_udp_port
= UDP_PORT_COLLECTD
;
152 static gint proto_collectd
= -1;
153 static gint tap_collectd
= -1;
155 static gint hf_collectd_type
= -1;
156 static gint hf_collectd_length
= -1;
157 static gint hf_collectd_data
= -1;
158 static gint hf_collectd_data_host
= -1;
159 static gint hf_collectd_data_time
= -1;
160 static gint hf_collectd_data_interval
= -1;
161 static gint hf_collectd_data_plugin
= -1;
162 static gint hf_collectd_data_plugin_inst
= -1;
163 static gint hf_collectd_data_type
= -1;
164 static gint hf_collectd_data_type_inst
= -1;
165 static gint hf_collectd_data_valcnt
= -1;
166 static gint hf_collectd_val_type
= -1;
167 static gint hf_collectd_val_counter
= -1;
168 static gint hf_collectd_val_gauge
= -1;
169 static gint hf_collectd_val_derive
= -1;
170 static gint hf_collectd_val_absolute
= -1;
171 static gint hf_collectd_val_unknown
= -1;
172 static gint hf_collectd_data_severity
= -1;
173 static gint hf_collectd_data_message
= -1;
174 static gint hf_collectd_data_sighash
= -1;
175 static gint hf_collectd_data_initvec
= -1;
176 static gint hf_collectd_data_username_len
= -1;
177 static gint hf_collectd_data_username
= -1;
178 static gint hf_collectd_data_encrypted
= -1;
180 static gint ett_collectd
= -1;
181 static gint ett_collectd_string
= -1;
182 static gint ett_collectd_integer
= -1;
183 static gint ett_collectd_part_value
= -1;
184 static gint ett_collectd_value
= -1;
185 static gint ett_collectd_valinfo
= -1;
186 static gint ett_collectd_signature
= -1;
187 static gint ett_collectd_encryption
= -1;
188 static gint ett_collectd_dispatch
= -1;
189 static gint ett_collectd_invalid_length
= -1;
190 static gint ett_collectd_unknown
= -1;
192 static gint st_collectd_packets
= -1;
193 static gint st_collectd_values
= -1;
194 static gint st_collectd_values_hosts
= -1;
195 static gint st_collectd_values_plugins
= -1;
196 static gint st_collectd_values_types
= -1;
198 static expert_field ei_collectd_type
= EI_INIT
;
199 static expert_field ei_collectd_invalid_length
= EI_INIT
;
200 static expert_field ei_collectd_data_valcnt
= EI_INIT
;
201 static expert_field ei_collectd_garbage
= EI_INIT
;
203 /* Prototype for the handoff function */
204 void proto_reg_handoff_collectd (void);
207 collectd_time_to_nstime (guint64 t
)
209 nstime_t nstime
= { 0, 0 };
210 nstime
.secs
= (time_t) (t
/ 1073741824);
211 nstime
.nsecs
= (int) (((double) (t
% 1073741824)) / 1.073741824);
217 collectd_stats_tree_init (stats_tree
*st
)
219 st_collectd_packets
= stats_tree_create_node (st
, "Packets", 0, FALSE
);
220 st_collectd_values
= stats_tree_create_node (st
, "Values", 0, TRUE
);
222 st_collectd_values_hosts
= stats_tree_create_pivot (st
, "By host",
224 st_collectd_values_plugins
= stats_tree_create_pivot (st
, "By plugin",
226 st_collectd_values_types
= stats_tree_create_pivot (st
, "By type",
228 } /* void collectd_stats_tree_init */
231 collectd_stats_tree_packet (stats_tree
*st
, packet_info
*pinfo _U_
,
232 epan_dissect_t
*edt _U_
, const void *user_data
)
234 const tap_data_t
*td
;
235 string_counter_t
*sc
;
237 td
= (const tap_data_t
*)user_data
;
241 tick_stat_node (st
, "Packets", 0, FALSE
);
242 increase_stat_node (st
, "Values", 0, TRUE
, td
->values_num
);
244 for (sc
= td
->hosts
; sc
!= NULL
; sc
= sc
->next
)
247 for (i
= 0; i
< sc
->count
; i
++)
248 stats_tree_tick_pivot (st
, st_collectd_values_hosts
,
252 for (sc
= td
->plugins
; sc
!= NULL
; sc
= sc
->next
)
255 for (i
= 0; i
< sc
->count
; i
++)
256 stats_tree_tick_pivot (st
, st_collectd_values_plugins
,
260 for (sc
= td
->types
; sc
!= NULL
; sc
= sc
->next
)
263 for (i
= 0; i
< sc
->count
; i
++)
264 stats_tree_tick_pivot (st
, st_collectd_values_types
,
269 } /* int collectd_stats_tree_packet */
272 collectd_stats_tree_register (void)
274 stats_tree_register ("collectd", "collectd", "Collectd", 0,
275 collectd_stats_tree_packet
,
276 collectd_stats_tree_init
, NULL
);
277 } /* void register_collectd_stat_trees */
280 collectd_proto_tree_add_assembled_metric (tvbuff_t
*tvb
,
281 gint offset
, gint length
,
282 value_data_t
const *vdispatch
, proto_tree
*root
)
284 proto_item
*root_item
;
288 root_item
= proto_tree_add_text (root
, tvb
, offset
+ 6, length
- 6,
290 PROTO_ITEM_SET_GENERATED (root_item
);
292 subtree
= proto_item_add_subtree (root_item
, ett_collectd_dispatch
);
294 proto_tree_add_string (subtree
, hf_collectd_data_host
, tvb
,
295 vdispatch
->host_off
, vdispatch
->host_len
,
296 STR_NONNULL (vdispatch
->host
));
298 proto_tree_add_string (subtree
, hf_collectd_data_plugin
, tvb
,
299 vdispatch
->plugin_off
, vdispatch
->plugin_len
,
300 STR_NONNULL (vdispatch
->plugin
));
302 if (vdispatch
->plugin_instance
)
303 proto_tree_add_string (subtree
,
304 hf_collectd_data_plugin_inst
, tvb
,
305 vdispatch
->plugin_instance_off
,
306 vdispatch
->plugin_instance_len
,
307 vdispatch
->plugin_instance
);
309 proto_tree_add_string (subtree
, hf_collectd_data_type
, tvb
,
310 vdispatch
->type_off
, vdispatch
->type_len
,
311 STR_NONNULL (vdispatch
->type
));
313 if (vdispatch
->type_instance
)
314 proto_tree_add_string (subtree
,
315 hf_collectd_data_type_inst
, tvb
,
316 vdispatch
->type_instance_off
,
317 vdispatch
->type_instance_len
,
318 vdispatch
->type_instance
);
320 nstime
= collectd_time_to_nstime (vdispatch
->time
);
321 proto_tree_add_time (subtree
, hf_collectd_data_time
, tvb
,
322 vdispatch
->time_off
, /* length = */ 8, &nstime
);
324 nstime
= collectd_time_to_nstime (vdispatch
->interval
);
325 proto_tree_add_time (subtree
, hf_collectd_data_interval
, tvb
,
326 vdispatch
->interval_off
, /* length = */ 8, &nstime
);
330 collectd_proto_tree_add_assembled_notification (tvbuff_t
*tvb
,
331 gint offset
, gint length
,
332 notify_data_t
const *ndispatch
, proto_tree
*root
)
334 proto_item
*root_item
;
338 root_item
= proto_tree_add_text (root
, tvb
, offset
+ 6, length
- 6,
339 "Assembled notification");
340 PROTO_ITEM_SET_GENERATED (root_item
);
342 subtree
= proto_item_add_subtree (root_item
, ett_collectd_dispatch
);
344 proto_tree_add_string (subtree
, hf_collectd_data_host
, tvb
,
345 ndispatch
->host_off
, ndispatch
->host_len
,
346 STR_NONNULL (ndispatch
->host
));
348 nstime
= collectd_time_to_nstime (ndispatch
->time
);
349 proto_tree_add_time (subtree
, hf_collectd_data_time
, tvb
,
350 ndispatch
->time_off
, /* length = */ 8, &nstime
);
352 proto_tree_add_uint64 (subtree
, hf_collectd_data_severity
, tvb
,
353 ndispatch
->severity_off
, /* length = */ 8,
354 ndispatch
->severity
);
356 proto_tree_add_string (subtree
, hf_collectd_data_message
, tvb
,
357 ndispatch
->message_off
, ndispatch
->message_len
,
362 dissect_collectd_string (tvbuff_t
*tvb
, packet_info
*pinfo
, gint type_hf
,
363 gint offset
, gint
*ret_offset
, gint
*ret_length
,
364 gchar
**ret_string
, proto_tree
*tree_root
,
365 proto_item
**ret_item
)
373 size
= tvb_reported_length_remaining (tvb
, offset
);
376 /* This should never happen, because `dissect_collectd' checks
377 * for this condition already. */
381 type
= tvb_get_ntohs(tvb
, offset
);
382 length
= tvb_get_ntohs(tvb
, offset
+ 2);
386 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
387 "collectd %s segment: Length = %i <BAD>",
388 val_to_str_const (type
, part_names
, "UNKNOWN"),
390 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
391 "String part with invalid part length: "
392 "Part is longer than rest of package.");
396 *ret_offset
= offset
+ 4;
397 *ret_length
= length
- 4;
399 *ret_string
= tvb_get_string (wmem_packet_scope(), tvb
, *ret_offset
, *ret_length
);
401 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
402 "collectd %s segment: \"%s\"",
403 val_to_str_const (type
, part_names
, "UNKNOWN"),
406 if (ret_item
!= NULL
)
409 pt
= proto_item_add_subtree (pi
, ett_collectd_string
);
410 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
411 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2, length
);
412 proto_tree_add_item (pt
, type_hf
, tvb
, *ret_offset
, *ret_length
, ENC_ASCII
|ENC_NA
);
415 } /* int dissect_collectd_string */
418 dissect_collectd_integer (tvbuff_t
*tvb
, packet_info
*pinfo
, gint type_hf
,
419 gint offset
, gint
*ret_offset
, guint64
*ret_value
,
420 proto_tree
*tree_root
, proto_item
**ret_item
)
428 size
= tvb_reported_length_remaining (tvb
, offset
);
431 /* This should never happen, because `dissect_collectd' checks
432 * for this condition already. */
436 type
= tvb_get_ntohs(tvb
, offset
);
437 length
= tvb_get_ntohs(tvb
, offset
+ 2);
441 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
442 "collectd %s segment: <BAD>",
443 val_to_str_const (type
, part_names
, "UNKNOWN"));
445 pt
= proto_item_add_subtree (pi
, ett_collectd_integer
);
446 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2,
448 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2,
450 proto_tree_add_expert_format(pt
, pinfo
, &ei_collectd_garbage
, tvb
, offset
+ 4, -1,
451 "Garbage at end of packet: Length = %i <BAD>",
459 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
460 "collectd %s segment: <BAD>",
461 val_to_str_const (type
, part_names
, "UNKNOWN"));
463 pt
= proto_item_add_subtree (pi
, ett_collectd_integer
);
464 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2,
466 pi
= proto_tree_add_uint (pt
, hf_collectd_length
, tvb
,
467 offset
+ 2, 2, length
);
468 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
469 "Invalid length field for an integer part.");
474 *ret_offset
= offset
+ 4;
475 *ret_value
= tvb_get_ntoh64 (tvb
, offset
+ 4);
477 /* Convert the version 4.* time format to the version 5.* time format. */
478 if ((type
== TYPE_TIME
) || (type
== TYPE_INTERVAL
))
479 *ret_value
*= 1073741824;
481 /* Create an entry in the protocol tree for this part. The value is
482 * printed depending on the "type" variable: TIME{,_HR} as absolute
483 * time, INTERVAL{,_HR} as relative time, uint64 otherwise. */
484 if ((type
== TYPE_TIME
) || (type
== TYPE_TIME_HR
))
489 nstime
= collectd_time_to_nstime (*ret_value
);
490 strtime
= abs_time_to_str (&nstime
, ABSOLUTE_TIME_LOCAL
, /* show_zone = */ TRUE
);
491 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
492 "collectd %s segment: %s",
493 val_to_str_const (type
, part_names
, "UNKNOWN"),
494 STR_NONNULL (strtime
));
496 else if ((type
== TYPE_INTERVAL
) || (type
== TYPE_INTERVAL_HR
))
501 nstime
= collectd_time_to_nstime (*ret_value
);
502 strtime
= rel_time_to_str (&nstime
);
503 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
504 "collectd %s segment: %s",
505 val_to_str_const (type
, part_names
, "UNKNOWN"),
510 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
511 "collectd %s segment: %"G_GINT64_MODIFIER
"u",
512 val_to_str_const (type
, part_names
, "UNKNOWN"),
516 if (ret_item
!= NULL
)
519 pt
= proto_item_add_subtree (pi
, ett_collectd_integer
);
520 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
521 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2,
523 if ((type
== TYPE_TIME
) || (type
== TYPE_INTERVAL
)
524 || (type
== TYPE_TIME_HR
) || (type
== TYPE_INTERVAL_HR
))
528 nstime
= collectd_time_to_nstime (*ret_value
);
529 proto_tree_add_time (pt
, type_hf
, tvb
, offset
+ 4, 8, &nstime
);
533 proto_tree_add_item (pt
, type_hf
, tvb
, offset
+ 4, 8, ENC_BIG_ENDIAN
);
537 } /* int dissect_collectd_integer */
540 dissect_collectd_values(tvbuff_t
*tvb
, gint msg_off
, gint val_cnt
,
541 proto_tree
*collectd_tree
)
544 proto_tree
*values_tree
, *value_tree
;
547 pi
= proto_tree_add_text (collectd_tree
, tvb
, msg_off
+ 6, val_cnt
* 9,
548 "%d value%s", val_cnt
,
549 plurality (val_cnt
, "", "s"));
551 values_tree
= proto_item_add_subtree (pi
, ett_collectd_value
);
553 for (i
= 0; i
< val_cnt
; i
++)
557 gint value_type_offset
;
560 /* Calculate the offsets of the type byte and the actual value. */
561 value_offset
= msg_off
+ 6
562 + val_cnt
/* value types */
563 + (i
* 8); /* previous values */
565 value_type_offset
= msg_off
+ 6 + i
;
566 value_type
= tvb_get_guint8 (tvb
, value_type_offset
);
568 switch (value_type
) {
569 case TYPE_VALUE_COUNTER
:
573 val64
= tvb_get_ntoh64 (tvb
, value_offset
);
574 pi
= proto_tree_add_text (values_tree
, tvb
, msg_off
+ 6,
576 "Counter: %"G_GINT64_MODIFIER
"u", val64
);
578 value_tree
= proto_item_add_subtree (pi
,
579 ett_collectd_valinfo
);
580 proto_tree_add_item (value_tree
, hf_collectd_val_type
,
581 tvb
, value_type_offset
, 1, ENC_BIG_ENDIAN
);
582 proto_tree_add_item (value_tree
,
583 hf_collectd_val_counter
, tvb
,
584 value_offset
, 8, ENC_BIG_ENDIAN
);
588 case TYPE_VALUE_GAUGE
:
592 val
= tvb_get_letohieee_double (tvb
, value_offset
);
593 pi
= proto_tree_add_text (values_tree
, tvb
, msg_off
+ 6,
597 value_tree
= proto_item_add_subtree (pi
,
598 ett_collectd_valinfo
);
599 proto_tree_add_item (value_tree
, hf_collectd_val_type
,
600 tvb
, value_type_offset
, 1, ENC_BIG_ENDIAN
);
601 /* Set the `little endian' flag to TRUE here, because
602 * collectd stores doubles in x86 representation. */
603 proto_tree_add_item (value_tree
, hf_collectd_val_gauge
,
604 tvb
, value_offset
, 8, ENC_LITTLE_ENDIAN
);
608 case TYPE_VALUE_DERIVE
:
612 val64
= tvb_get_ntoh64 (tvb
, value_offset
);
613 pi
= proto_tree_add_text (values_tree
, tvb
, msg_off
+ 6,
615 "Derive: %"G_GINT64_MODIFIER
"i", val64
);
617 value_tree
= proto_item_add_subtree (pi
,
618 ett_collectd_valinfo
);
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
,
622 hf_collectd_val_derive
, tvb
,
623 value_offset
, 8, ENC_BIG_ENDIAN
);
627 case TYPE_VALUE_ABSOLUTE
:
631 val64
= tvb_get_ntoh64 (tvb
, value_offset
);
632 pi
= proto_tree_add_text (values_tree
, tvb
, msg_off
+ 6,
634 "Absolute: %"G_GINT64_MODIFIER
"u", val64
);
636 value_tree
= proto_item_add_subtree (pi
,
637 ett_collectd_valinfo
);
638 proto_tree_add_item (value_tree
, hf_collectd_val_type
,
639 tvb
, value_type_offset
, 1, ENC_BIG_ENDIAN
);
640 proto_tree_add_item (value_tree
,
641 hf_collectd_val_absolute
, tvb
,
642 value_offset
, 8, ENC_BIG_ENDIAN
);
650 val64
= tvb_get_ntoh64 (tvb
, value_offset
);
651 pi
= proto_tree_add_text (values_tree
, tvb
, msg_off
+ 6,
653 "Unknown: %"G_GINT64_MODIFIER
"x",
656 value_tree
= proto_item_add_subtree (pi
,
657 ett_collectd_valinfo
);
658 proto_tree_add_item (value_tree
, hf_collectd_val_type
,
659 tvb
, value_type_offset
, 1, ENC_BIG_ENDIAN
);
660 proto_tree_add_item (value_tree
, hf_collectd_val_unknown
,
661 tvb
, value_offset
, 8, ENC_BIG_ENDIAN
);
664 } /* switch (value_type) */
665 } /* for (i = 0; i < val_cnt; i++) */
666 } /* void dissect_collectd_values */
669 dissect_collectd_part_values (tvbuff_t
*tvb
, packet_info
*pinfo
, gint offset
,
670 value_data_t
*vdispatch
, proto_tree
*tree_root
)
678 gint corrected_values_count
;
680 size
= tvb_reported_length_remaining (tvb
, offset
);
683 /* This should never happen, because `dissect_collectd' checks
684 * for this condition already. */
688 type
= tvb_get_ntohs (tvb
, offset
);
689 length
= tvb_get_ntohs (tvb
, offset
+ 2);
693 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
694 "collectd %s segment: <BAD>",
695 val_to_str_const (type
, part_names
, "UNKNOWN"));
697 pt
= proto_item_add_subtree (pi
, ett_collectd_part_value
);
698 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
699 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2,
701 proto_tree_add_expert_format(pt
, pinfo
, &ei_collectd_garbage
, tvb
, offset
+ 4, -1,
702 "Garbage at end of packet: Length = %i <BAD>",
707 if ((length
< 15) || ((length
% 9) != 6))
709 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
710 "collectd %s segment: <BAD>",
711 val_to_str_const (type
, part_names
, "UNKNOWN"));
713 pt
= proto_item_add_subtree (pi
, ett_collectd_part_value
);
714 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
715 pi
= proto_tree_add_uint (pt
, hf_collectd_length
, tvb
,
716 offset
+ 2, 2, length
);
717 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
718 "Invalid length field for a values part.");
723 values_count
= tvb_get_ntohs (tvb
, offset
+ 4);
724 corrected_values_count
= (length
- 6) / 9;
726 if (values_count
!= corrected_values_count
)
728 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
729 "collectd %s segment: %d (%d) value%s <BAD>",
730 val_to_str_const (type
, part_names
, "UNKNOWN"),
731 values_count
, corrected_values_count
,
732 plurality(values_count
, "", "s"));
736 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
737 "collectd %s segment: %d value%s",
738 val_to_str_const (type
, part_names
, "UNKNOWN"),
740 plurality(values_count
, "", "s"));
743 pt
= proto_item_add_subtree (pi
, ett_collectd_part_value
);
744 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
745 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2, length
);
747 pi
= proto_tree_add_item (pt
, hf_collectd_data_valcnt
, tvb
,
748 offset
+ 4, 2, ENC_BIG_ENDIAN
);
749 if (values_count
!= corrected_values_count
)
750 expert_add_info(pinfo
, pi
, &ei_collectd_data_valcnt
);
752 values_count
= corrected_values_count
;
754 dissect_collectd_values (tvb
, offset
, values_count
, pt
);
755 collectd_proto_tree_add_assembled_metric (tvb
, offset
+ 6, length
- 6,
759 } /* void dissect_collectd_part_values */
762 dissect_collectd_signature (tvbuff_t
*tvb
, packet_info
*pinfo
,
763 gint offset
, proto_tree
*tree_root
)
771 size
= tvb_reported_length_remaining (tvb
, offset
);
774 /* This should never happen, because `dissect_collectd' checks
775 * for this condition already. */
779 type
= tvb_get_ntohs (tvb
, offset
);
780 length
= tvb_get_ntohs (tvb
, offset
+ 2);
782 if (size
< 36) /* remaining packet size too small for signature */
784 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
785 "collectd %s segment: <BAD>",
786 val_to_str_const (type
, part_names
, "UNKNOWN"));
788 pt
= proto_item_add_subtree (pi
, ett_collectd_signature
);
789 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
790 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2,
792 proto_tree_add_expert_format(pt
, pinfo
, &ei_collectd_garbage
, tvb
, offset
+ 4, -1,
793 "Garbage at end of packet: Length = %i <BAD>",
800 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
801 "collectd %s segment: <BAD>",
802 val_to_str_const (type
, part_names
, "UNKNOWN"));
804 pt
= proto_item_add_subtree (pi
, ett_collectd_signature
);
805 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
806 pi
= proto_tree_add_uint (pt
, hf_collectd_length
, tvb
,
807 offset
+ 2, 2, length
);
808 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
809 "Invalid length field for a signature part.");
814 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
815 "collectd %s segment: HMAC-SHA-256",
816 val_to_str_const (type
, part_names
, "UNKNOWN"));
818 pt
= proto_item_add_subtree (pi
, ett_collectd_signature
);
819 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
820 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2,
822 proto_tree_add_item (pt
, hf_collectd_data_sighash
, tvb
, offset
+ 4, 32, ENC_NA
);
823 proto_tree_add_item (pt
, hf_collectd_data_username
, tvb
, offset
+ 36, length
- 36, ENC_ASCII
|ENC_NA
);
826 } /* int dissect_collectd_signature */
829 dissect_collectd_encrypted (tvbuff_t
*tvb
, packet_info
*pinfo
,
830 gint offset
, proto_tree
*tree_root
)
837 gint username_length
;
839 size
= tvb_reported_length_remaining (tvb
, offset
);
842 /* This should never happen, because `dissect_collectd' checks
843 * for this condition already. */
847 type
= tvb_get_ntohs (tvb
, offset
);
848 length
= tvb_get_ntohs (tvb
, offset
+ 2);
850 if (size
< 42) /* remaining packet size too small for signature */
852 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
853 "collectd %s segment: <BAD>",
854 val_to_str_const (type
, part_names
, "UNKNOWN"));
856 pt
= proto_item_add_subtree (pi
, ett_collectd_encryption
);
857 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
858 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2,
860 proto_tree_add_expert_format(pt
, pinfo
, &ei_collectd_garbage
, tvb
, offset
+ 4, -1,
861 "Garbage at end of packet: Length = %i <BAD>",
868 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
869 "collectd %s segment: <BAD>",
870 val_to_str_const (type
, part_names
, "UNKNOWN"));
872 pt
= proto_item_add_subtree (pi
, ett_collectd_encryption
);
873 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
874 pi
= proto_tree_add_uint (pt
, hf_collectd_length
, tvb
,
875 offset
+ 2, 2, length
);
876 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
877 "Invalid length field for an encryption part.");
882 username_length
= tvb_get_ntohs (tvb
, offset
+ 4);
883 if (username_length
> (length
- 42))
885 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, -1,
886 "collectd %s segment: <BAD>",
887 val_to_str_const (type
, part_names
, "UNKNOWN"));
889 pt
= proto_item_add_subtree (pi
, ett_collectd_encryption
);
890 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
891 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
,
892 offset
+ 2, 2, length
);
893 pi
= proto_tree_add_uint (pt
, hf_collectd_data_username_len
, tvb
,
894 offset
+ 4, 2, length
);
895 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
896 "Invalid username length field for an encryption part.");
901 pi
= proto_tree_add_text (tree_root
, tvb
, offset
, length
,
902 "collectd %s segment: AES-256",
903 val_to_str_const (type
, part_names
, "UNKNOWN"));
905 pt
= proto_item_add_subtree (pi
, ett_collectd_encryption
);
906 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
, 2, type
);
907 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
, offset
+ 2, 2, length
);
908 proto_tree_add_uint (pt
, hf_collectd_data_username_len
, tvb
, offset
+ 4, 2, username_length
);
909 proto_tree_add_item (pt
, hf_collectd_data_username
, tvb
, offset
+ 6, username_length
, ENC_ASCII
|ENC_NA
);
910 proto_tree_add_item (pt
, hf_collectd_data_initvec
, tvb
,
911 offset
+ (6 + username_length
), 16, ENC_NA
);
912 proto_tree_add_item (pt
, hf_collectd_data_encrypted
, tvb
,
913 offset
+ (22 + username_length
),
914 length
- (22 + username_length
), ENC_NA
);
917 } /* int dissect_collectd_encrypted */
920 stats_account_string (string_counter_t
**ret_list
, const gchar
*new_value
)
922 string_counter_t
*entry
;
924 if (ret_list
== NULL
)
927 if (new_value
== NULL
)
928 new_value
= "(null)";
930 for (entry
= *ret_list
; entry
!= NULL
; entry
= entry
->next
)
931 if (strcmp (new_value
, entry
->string
) == 0)
937 entry
= (string_counter_t
*)wmem_alloc0 (wmem_packet_scope(), sizeof (*entry
));
938 entry
->string
= wmem_strdup (wmem_packet_scope(), new_value
);
940 entry
->next
= *ret_list
;
948 dissect_collectd (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
950 static tap_data_t tap_data
;
954 gchar
*pkt_host
= NULL
;
955 gint pkt_plugins
= 0, pkt_values
= 0, pkt_messages
= 0, pkt_unknown
= 0, pkt_errors
= 0;
956 value_data_t vdispatch
;
957 notify_data_t ndispatch
;
960 proto_tree
*collectd_tree
;
963 memset(&vdispatch
, '\0', sizeof(vdispatch
));
964 memset(&ndispatch
, '\0', sizeof(ndispatch
));
966 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "collectd");
967 col_clear(pinfo
->cinfo
, COL_INFO
);
970 size
= tvb_reported_length(tvb
);
972 /* create the collectd protocol tree */
973 pi
= proto_tree_add_item(tree
, proto_collectd
, tvb
, 0, -1, ENC_NA
);
974 collectd_tree
= proto_item_add_subtree(pi
, ett_collectd
);
976 memset (&tap_data
, 0, sizeof (tap_data
));
979 while ((size
> 0) && (status
== 0))
985 /* Let's handle the easy case first real quick: All we do here
986 * is extract a host name and count the number of values,
987 * plugins and notifications. The payload is not checked at
988 * all, but the same checks are run on the part_length stuff -
989 * it's important to keep an eye on that. */
992 /* Check for garbage at end of packet. */
999 part_type
= tvb_get_ntohs (tvb
, offset
);
1000 part_length
= tvb_get_ntohs (tvb
, offset
+2);
1002 /* Check if part_length is in the valid range. */
1003 if ((part_length
< 4) || (part_length
> size
))
1009 switch (part_type
) {
1011 vdispatch
.host
= tvb_get_string (wmem_packet_scope(), tvb
,
1012 offset
+ 4, part_length
- 4);
1013 if (pkt_host
== NULL
)
1014 pkt_host
= vdispatch
.host
;
1020 vdispatch
.plugin
= tvb_get_string (wmem_packet_scope(), tvb
,
1021 offset
+ 4, part_length
- 4);
1024 case TYPE_PLUGIN_INSTANCE
:
1027 vdispatch
.type
= tvb_get_string (wmem_packet_scope(), tvb
,
1028 offset
+ 4, part_length
- 4);
1030 case TYPE_TYPE_INSTANCE
:
1033 case TYPE_INTERVAL_HR
:
1039 tap_data
.values_num
++;
1040 stats_account_string (&tap_data
.hosts
,
1042 stats_account_string (&tap_data
.plugins
,
1044 stats_account_string (&tap_data
.types
,
1058 offset
+= part_length
;
1059 size
-= part_length
;
1063 /* Now we do the same steps again, but much more thoroughly. */
1065 /* Check if there are at least four bytes left first.
1066 * Four bytes are used to read the type and the length
1067 * of the next part. If there's less, there's some garbage
1068 * at the end of the packet. */
1071 proto_tree_add_expert_format(pi
, pinfo
, &ei_collectd_garbage
, tvb
,
1073 "Garbage at end of packet: Length = %i <BAD>",
1079 /* dissect a message entry */
1080 part_type
= tvb_get_ntohs (tvb
, offset
);
1081 part_length
= tvb_get_ntohs (tvb
, offset
+ 2);
1083 /* Check if the length of the part is in the valid range. Don't
1084 * confuse this with the above: Here we check the information
1085 * provided in the packet.. */
1086 if ((part_length
< 4) || (part_length
> size
))
1088 pi
= proto_tree_add_text (collectd_tree
, tvb
,
1089 offset
, part_length
,
1090 "collectd %s segment: Length = %i <BAD>",
1091 val_to_str_const (part_type
, part_names
, "UNKNOWN"),
1094 pt
= proto_item_add_subtree (pi
, ett_collectd_invalid_length
);
1095 proto_tree_add_uint (pt
, hf_collectd_type
, tvb
, offset
,
1097 pi
= proto_tree_add_uint (pt
, hf_collectd_length
, tvb
,
1098 offset
+ 2, 2, part_length
);
1100 if (part_length
< 4)
1101 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
1102 "Bad part length: Is %i, expected at least 4",
1105 expert_add_info_format(pinfo
, pi
, &ei_collectd_invalid_length
,
1106 "Bad part length: Larger than remaining packet size.");
1112 /* The header information looks okay, let's tend to the actual
1113 * payload in this part. */
1114 switch (part_type
) {
1117 status
= dissect_collectd_string (tvb
, pinfo
,
1118 hf_collectd_data_host
,
1120 &vdispatch
.host_off
,
1121 &vdispatch
.host_len
,
1123 collectd_tree
, /* item = */ NULL
);
1128 if (pkt_host
== NULL
)
1129 pkt_host
= vdispatch
.host
;
1130 ndispatch
.host_off
= vdispatch
.host_off
;
1131 ndispatch
.host_len
= vdispatch
.host_len
;
1132 ndispatch
.host
= vdispatch
.host
;
1140 status
= dissect_collectd_string (tvb
, pinfo
,
1141 hf_collectd_data_plugin
,
1143 &vdispatch
.plugin_off
,
1144 &vdispatch
.plugin_len
,
1146 collectd_tree
, /* item = */ NULL
);
1155 case TYPE_PLUGIN_INSTANCE
:
1157 status
= dissect_collectd_string (tvb
, pinfo
,
1158 hf_collectd_data_plugin_inst
,
1160 &vdispatch
.plugin_instance_off
,
1161 &vdispatch
.plugin_instance_len
,
1162 &vdispatch
.plugin_instance
,
1163 collectd_tree
, /* item = */ NULL
);
1172 status
= dissect_collectd_string (tvb
, pinfo
,
1173 hf_collectd_data_type
,
1175 &vdispatch
.type_off
,
1176 &vdispatch
.type_len
,
1178 collectd_tree
, /* item = */ NULL
);
1185 case TYPE_TYPE_INSTANCE
:
1187 status
= dissect_collectd_string (tvb
, pinfo
,
1188 hf_collectd_data_type_inst
,
1190 &vdispatch
.type_instance_off
,
1191 &vdispatch
.type_instance_len
,
1192 &vdispatch
.type_instance
,
1193 collectd_tree
, /* item = */ NULL
);
1204 status
= dissect_collectd_integer (tvb
, pinfo
,
1205 hf_collectd_data_time
,
1207 &vdispatch
.time_off
,
1209 collectd_tree
, &pi
);
1217 case TYPE_INTERVAL_HR
:
1219 status
= dissect_collectd_integer (tvb
, pinfo
,
1220 hf_collectd_data_interval
,
1222 &vdispatch
.interval_off
,
1223 &vdispatch
.interval
,
1224 collectd_tree
, /* item = */ NULL
);
1233 status
= dissect_collectd_part_values (tvb
, pinfo
,
1242 tap_data
.values_num
++;
1243 stats_account_string (&tap_data
.hosts
,
1245 stats_account_string (&tap_data
.plugins
,
1247 stats_account_string (&tap_data
.types
,
1256 status
= dissect_collectd_string (tvb
, pinfo
,
1257 hf_collectd_data_message
,
1259 &ndispatch
.message_off
,
1260 &ndispatch
.message_len
,
1262 collectd_tree
, &pi
);
1270 pt
= proto_item_get_subtree (pi
);
1272 collectd_proto_tree_add_assembled_notification (tvb
,
1273 offset
+ 4, part_length
- 1,
1282 status
= dissect_collectd_integer (tvb
, pinfo
,
1283 hf_collectd_data_severity
,
1285 &ndispatch
.severity_off
,
1286 &ndispatch
.severity
,
1287 collectd_tree
, &pi
);
1292 proto_item_set_text (pi
,
1293 "collectd SEVERITY segment: "
1294 "%s (%"G_GINT64_MODIFIER
"u)",
1295 val64_to_str_const (ndispatch
.severity
, severity_names
, "UNKNOWN"),
1296 ndispatch
.severity
);
1302 case TYPE_SIGN_SHA256
:
1304 status
= dissect_collectd_signature (tvb
, pinfo
,
1313 case TYPE_ENCR_AES256
:
1315 status
= dissect_collectd_encrypted (tvb
, pinfo
,
1316 offset
, collectd_tree
);
1326 pi
= proto_tree_add_text (collectd_tree
, tvb
,
1327 offset
, part_length
,
1328 "collectd %s segment: %i bytes",
1329 val_to_str_const(part_type
, part_names
, "UNKNOWN"),
1332 pt
= proto_item_add_subtree(pi
, ett_collectd_unknown
);
1333 pi
= proto_tree_add_uint (pt
, hf_collectd_type
, tvb
,
1334 offset
, 2, part_type
);
1335 proto_tree_add_uint (pt
, hf_collectd_length
, tvb
,
1336 offset
+ 2, 2, part_length
);
1337 proto_tree_add_item (pt
, hf_collectd_data
, tvb
,
1338 offset
+ 4, part_length
- 4, ENC_NA
);
1340 expert_add_info_format(pinfo
, pi
, &ei_collectd_type
,
1341 "Unknown part type %#x. Cannot decode data.",
1344 } /* switch (part_type) */
1346 offset
+= part_length
;
1347 size
-= part_length
;
1348 } /* while ((size > 4) && (status == 0)) */
1350 if (pkt_errors
&& pkt_unknown
)
1351 col_add_fstr (pinfo
->cinfo
, COL_INFO
,
1352 "Host=%s, %2d value%s for %d plugin%s %d message%s %d unknown, %d error%s",
1354 pkt_values
, plurality (pkt_values
, " ", "s"),
1355 pkt_plugins
, plurality (pkt_plugins
, ", ", "s,"),
1356 pkt_messages
, plurality (pkt_messages
, ", ", "s,"),
1358 pkt_errors
, plurality (pkt_errors
, "", "s"));
1359 else if (pkt_errors
)
1360 col_add_fstr (pinfo
->cinfo
, COL_INFO
, "Host=%s, %2d value%s for %d plugin%s %d message%s %d error%s",
1362 pkt_values
, plurality (pkt_values
, " ", "s"),
1363 pkt_plugins
, plurality (pkt_plugins
, ", ", "s,"),
1364 pkt_messages
, plurality (pkt_messages
, ", ", "s,"),
1365 pkt_errors
, plurality (pkt_errors
, "", "s"));
1366 else if (pkt_unknown
)
1367 col_add_fstr (pinfo
->cinfo
, COL_INFO
,
1368 "Host=%s, %2d value%s for %d plugin%s %d message%s %d unknown",
1370 pkt_values
, plurality (pkt_values
, " ", "s"),
1371 pkt_plugins
, plurality (pkt_plugins
, ", ", "s,"),
1372 pkt_messages
, plurality (pkt_messages
, ", ", "s,"),
1375 col_add_fstr (pinfo
->cinfo
, COL_INFO
, "Host=%s, %2d value%s for %d plugin%s %d message%s",
1377 pkt_values
, plurality (pkt_values
, " ", "s"),
1378 pkt_plugins
, plurality (pkt_plugins
, ", ", "s,"),
1379 pkt_messages
, plurality (pkt_messages
, "", "s"));
1381 /* Dispatch tap data. */
1382 tap_queue_packet (tap_collectd
, pinfo
, &tap_data
);
1383 } /* void dissect_collectd */
1385 void proto_register_collectd(void)
1387 module_t
*collectd_module
;
1388 expert_module_t
* expert_collectd
;
1390 /* Setup list of header fields */
1391 static hf_register_info hf
[] = {
1392 { &hf_collectd_type
,
1393 { "Type", "collectd.type", FT_UINT16
, BASE_HEX
,
1394 VALS(part_names
), 0x0, NULL
, HFILL
}
1396 { &hf_collectd_length
,
1397 { "Length", "collectd.len", FT_UINT16
, BASE_DEC
,
1398 NULL
, 0x0, NULL
, HFILL
}
1400 { &hf_collectd_data
,
1401 { "Payload", "collectd.data", FT_BYTES
, BASE_NONE
,
1402 NULL
, 0x0, NULL
, HFILL
}
1404 { &hf_collectd_data_host
,
1405 { "Host name", "collectd.data.host", FT_STRING
, BASE_NONE
,
1406 NULL
, 0x0, NULL
, HFILL
}
1408 { &hf_collectd_data_interval
,
1409 { "Interval", "collectd.data.interval", FT_RELATIVE_TIME
, BASE_NONE
,
1410 NULL
, 0x0, NULL
, HFILL
}
1412 { &hf_collectd_data_time
,
1413 { "Timestamp", "collectd.data.time", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
,
1414 NULL
, 0x0, NULL
, HFILL
}
1416 { &hf_collectd_data_plugin
,
1417 { "Plugin", "collectd.data.plugin", FT_STRING
, BASE_NONE
,
1418 NULL
, 0x0, NULL
, HFILL
}
1420 { &hf_collectd_data_plugin_inst
,
1421 { "Plugin instance", "collectd.data.plugin.inst", FT_STRING
, BASE_NONE
,
1422 NULL
, 0x0, NULL
, HFILL
}
1424 { &hf_collectd_data_type
,
1425 { "Type", "collectd.data.type", FT_STRING
, BASE_NONE
,
1426 NULL
, 0x0, NULL
, HFILL
}
1428 { &hf_collectd_data_type_inst
,
1429 { "Type instance", "collectd.data.type.inst", FT_STRING
, BASE_NONE
,
1430 NULL
, 0x0, NULL
, HFILL
}
1432 { &hf_collectd_data_valcnt
,
1433 { "Value count", "collectd.data.valcnt", FT_UINT16
, BASE_DEC
,
1434 NULL
, 0x0, NULL
, HFILL
}
1436 { &hf_collectd_val_type
,
1437 { "Value type", "collectd.val.type", FT_UINT8
, BASE_HEX
,
1438 VALS(valuetypenames
), 0x0, NULL
, HFILL
}
1440 { &hf_collectd_val_counter
,
1441 { "Counter value", "collectd.val.counter", FT_UINT64
, BASE_DEC
,
1442 NULL
, 0x0, NULL
, HFILL
}
1444 { &hf_collectd_val_gauge
,
1445 { "Gauge value", "collectd.val.gauge", FT_DOUBLE
, BASE_NONE
,
1446 NULL
, 0x0, NULL
, HFILL
}
1448 { &hf_collectd_val_derive
,
1449 { "Derive value", "collectd.val.derive", FT_INT64
, BASE_DEC
,
1450 NULL
, 0x0, NULL
, HFILL
}
1452 { &hf_collectd_val_absolute
,
1453 { "Absolute value", "collectd.val.absolute", FT_UINT64
, BASE_DEC
,
1454 NULL
, 0x0, NULL
, HFILL
}
1456 { &hf_collectd_val_unknown
,
1457 { "Value of unknown type", "collectd.val.unknown", FT_UINT64
, BASE_HEX
,
1458 NULL
, 0x0, NULL
, HFILL
}
1460 { &hf_collectd_data_severity
,
1461 { "Severity", "collectd.data.severity", FT_UINT64
, BASE_HEX
| BASE_VAL64_STRING
,
1462 VALS(severity_names
),
1465 { &hf_collectd_data_message
,
1466 { "Message", "collectd.data.message", FT_STRING
, BASE_NONE
,
1467 NULL
, 0x0, NULL
, HFILL
}
1469 { &hf_collectd_data_sighash
,
1470 { "Signature", "collectd.data.sighash", FT_BYTES
, BASE_NONE
,
1471 NULL
, 0x0, NULL
, HFILL
}
1473 { &hf_collectd_data_initvec
,
1474 { "Init vector", "collectd.data.initvec", FT_BYTES
, BASE_NONE
,
1475 NULL
, 0x0, NULL
, HFILL
}
1477 { &hf_collectd_data_username_len
,
1478 { "Username length", "collectd.data.username_length", FT_UINT16
, BASE_DEC
,
1479 NULL
, 0x0, NULL
, HFILL
}
1481 { &hf_collectd_data_username
,
1482 { "Username", "collectd.data.username", FT_STRING
, BASE_NONE
,
1483 NULL
, 0x0, NULL
, HFILL
}
1485 { &hf_collectd_data_encrypted
,
1486 { "Encrypted data", "collectd.data.encrypted", FT_BYTES
, BASE_NONE
,
1487 NULL
, 0x0, NULL
, HFILL
}
1491 /* Setup protocol subtree array */
1492 static gint
*ett
[] = {
1494 &ett_collectd_string
,
1495 &ett_collectd_integer
,
1496 &ett_collectd_part_value
,
1497 &ett_collectd_value
,
1498 &ett_collectd_valinfo
,
1499 &ett_collectd_signature
,
1500 &ett_collectd_encryption
,
1501 &ett_collectd_dispatch
,
1502 &ett_collectd_invalid_length
,
1503 &ett_collectd_unknown
,
1506 static ei_register_info ei
[] = {
1507 { &ei_collectd_invalid_length
, { "collectd.invalid_length", PI_MALFORMED
, PI_ERROR
, "Invalid length", EXPFILL
}},
1508 { &ei_collectd_garbage
, { "collectd.garbage", PI_MALFORMED
, PI_ERROR
, "Garbage at end of packet", EXPFILL
}},
1509 { &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
}},
1510 { &ei_collectd_type
, { "collectd.type.unknown", PI_UNDECODED
, PI_NOTE
, "Unknown part type", EXPFILL
}},
1513 /* Register the protocol name and description */
1514 proto_collectd
= proto_register_protocol("collectd network data", "collectd", "collectd");
1516 /* Required function calls to register the header fields and subtrees used */
1517 proto_register_field_array(proto_collectd
, hf
, array_length(hf
));
1518 proto_register_subtree_array(ett
, array_length(ett
));
1519 expert_collectd
= expert_register_protocol(proto_collectd
);
1520 expert_register_field_array(expert_collectd
, ei
, array_length(ei
));
1522 tap_collectd
= register_tap ("collectd");
1525 * Create an unsigned integer preference to allow the user to specify the
1526 * UDP port on which to capture DIS packets.
1528 collectd_module
= prefs_register_protocol (proto_collectd
,
1529 proto_reg_handoff_collectd
);
1531 prefs_register_uint_preference (collectd_module
, "udp.port",
1532 "collectd UDP port",
1533 "Set the UDP port for collectd messages",
1534 10, &collectd_udp_port
);
1535 } /* void proto_register_collectd */
1537 void proto_reg_handoff_collectd (void)
1539 static gboolean first_run
= TRUE
;
1540 static gint registered_udp_port
= -1;
1541 static dissector_handle_t collectd_handle
;
1544 collectd_handle
= create_dissector_handle (dissect_collectd
,
1547 /* Change the dissector registration if the preferences have been
1549 if (registered_udp_port
!= -1)
1550 dissector_delete_uint ("udp.port", registered_udp_port
,
1553 dissector_add_uint ("udp.port", collectd_udp_port
, collectd_handle
);
1554 registered_udp_port
= collectd_udp_port
;
1557 collectd_stats_tree_register ();
1560 } /* void proto_reg_handoff_collectd */