Bug Summary

File:epan/dissectors/packet-collectd.c
Warning:line 948, column 4
1st function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-collectd.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-20/lib/clang/20 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/epan -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-07-30-100434-3867-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-collectd.c
1/* packet-collectd.c
2 * Routines for collectd (http://collectd.org/) network plugin dissection
3 *
4 * https://github.com/collectd/collectd/wiki/Binary-protocol
5 *
6 * Copyright 2008 Bruno Premont <bonbons at linux-vserver.org>
7 * Copyright 2009-2013 Florian Forster <octo at collectd.org>
8 *
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
12 *
13 * SPDX-License-Identifier: GPL-2.0-or-later
14 */
15
16#include "config.h"
17
18#include <epan/packet.h>
19#include <epan/expert.h>
20#include <epan/proto_data.h>
21#include <epan/stats_tree.h>
22#include <epan/to_str.h>
23
24#include <wsutil/str_util.h>
25
26#define STR_NONNULL(str)((str) ? ((const char*)str) : "(null)") ((str) ? ((const char*)str) : "(null)")
27
28#define TYPE_HOST0x0000 0x0000
29#define TYPE_TIME0x0001 0x0001
30#define TYPE_TIME_HR0x0008 0x0008
31#define TYPE_PLUGIN0x0002 0x0002
32#define TYPE_PLUGIN_INSTANCE0x0003 0x0003
33#define TYPE_TYPE0x0004 0x0004
34#define TYPE_TYPE_INSTANCE0x0005 0x0005
35#define TYPE_VALUES0x0006 0x0006
36#define TYPE_INTERVAL0x0007 0x0007
37#define TYPE_INTERVAL_HR0x0009 0x0009
38#define TYPE_MESSAGE0x0100 0x0100
39#define TYPE_SEVERITY0x0101 0x0101
40#define TYPE_SIGN_SHA2560x0200 0x0200
41#define TYPE_ENCR_AES2560x0210 0x0210
42
43void proto_register_collectd(void);
44
45static dissector_handle_t collectd_handle;
46
47#define TAP_DATA_KEY0 0
48#define COL_DATA_KEY1 1
49
50typedef struct value_data_s {
51 const uint8_t *host;
52 int host_off;
53 int host_len;
54 uint64_t time_value;
55 int time_off;
56 uint64_t interval;
57 int interval_off;
58 const uint8_t *plugin;
59 int plugin_off;
60 int plugin_len;
61 const uint8_t *plugin_instance;
62 int plugin_instance_off;
63 int plugin_instance_len;
64 const uint8_t *type;
65 int type_off;
66 int type_len;
67 const uint8_t *type_instance;
68 int type_instance_off;
69 int type_instance_len;
70} value_data_t;
71
72typedef struct notify_data_s {
73 const uint8_t *host;
74 int host_off;
75 int host_len;
76 uint64_t time_value;
77 int time_off;
78 uint64_t severity;
79 int severity_off;
80 const uint8_t *message;
81 int message_off;
82 int message_len;
83} notify_data_t;
84
85struct string_counter_s;
86typedef struct string_counter_s string_counter_t;
87struct string_counter_s
88{
89 const char *string;
90 int count;
91 string_counter_t *next;
92};
93
94typedef struct tap_data_s {
95 int values_num;
96
97 string_counter_t *hosts;
98 string_counter_t *plugins;
99 string_counter_t *types;
100} tap_data_t;
101
102typedef struct column_data_s {
103 unsigned pkt_plugins;
104 unsigned pkt_values;
105 unsigned pkt_messages;
106 unsigned pkt_unknown;
107 unsigned pkt_errors;
108
109 const uint8_t *pkt_host;
110} column_data_t;
111
112static const value_string part_names[] = {
113 { TYPE_VALUES0x0006, "VALUES" },
114 { TYPE_TIME0x0001, "TIME" },
115 { TYPE_TIME_HR0x0008, "TIME_HR" },
116 { TYPE_INTERVAL0x0007, "INTERVAL" },
117 { TYPE_INTERVAL_HR0x0009, "INTERVAL_HR" },
118 { TYPE_HOST0x0000, "HOST" },
119 { TYPE_PLUGIN0x0002, "PLUGIN" },
120 { TYPE_PLUGIN_INSTANCE0x0003, "PLUGIN_INSTANCE" },
121 { TYPE_TYPE0x0004, "TYPE" },
122 { TYPE_TYPE_INSTANCE0x0005, "TYPE_INSTANCE" },
123 { TYPE_MESSAGE0x0100, "MESSAGE" },
124 { TYPE_SEVERITY0x0101, "SEVERITY" },
125 { TYPE_SIGN_SHA2560x0200, "SIGNATURE" },
126 { TYPE_ENCR_AES2560x0210, "ENCRYPTED_DATA" },
127 { 0, NULL((void*)0) }
128};
129
130#define TYPE_VALUE_COUNTER0x00 0x00
131#define TYPE_VALUE_GAUGE0x01 0x01
132#define TYPE_VALUE_DERIVE0x02 0x02
133#define TYPE_VALUE_ABSOLUTE0x03 0x03
134static const value_string valuetypenames[] = {
135 { TYPE_VALUE_COUNTER0x00, "COUNTER" },
136 { TYPE_VALUE_GAUGE0x01, "GAUGE" },
137 { TYPE_VALUE_DERIVE0x02, "DERIVE" },
138 { TYPE_VALUE_ABSOLUTE0x03, "ABSOLUTE" },
139 { 0, NULL((void*)0) }
140};
141
142#define SEVERITY_FAILURE0x01 0x01
143#define SEVERITY_WARNING0x02 0x02
144#define SEVERITY_OKAY0x04 0x04
145static const val64_string severity_names[] = {
146 { SEVERITY_FAILURE0x01, "FAILURE" },
147 { SEVERITY_WARNING0x02, "WARNING" },
148 { SEVERITY_OKAY0x04, "OKAY" },
149 { 0, NULL((void*)0) }
150};
151
152#define UDP_PORT_COLLECTD25826 25826 /* Not IANA registered */
153
154static int proto_collectd;
155static int tap_collectd = -1;
156
157static int hf_collectd_type;
158static int hf_collectd_length;
159static int hf_collectd_data;
160static int hf_collectd_data_host;
161static int hf_collectd_data_time;
162static int hf_collectd_data_interval;
163static int hf_collectd_data_plugin;
164static int hf_collectd_data_plugin_inst;
165static int hf_collectd_data_type;
166static int hf_collectd_data_type_inst;
167static int hf_collectd_data_valcnt;
168static int hf_collectd_val_type;
169static int hf_collectd_val_counter;
170static int hf_collectd_val_gauge;
171static int hf_collectd_val_derive;
172static int hf_collectd_val_absolute;
173static int hf_collectd_val_unknown;
174static int hf_collectd_data_severity;
175static int hf_collectd_data_message;
176static int hf_collectd_data_sighash;
177static int hf_collectd_data_initvec;
178static int hf_collectd_data_username_len;
179static int hf_collectd_data_username;
180static int hf_collectd_data_encrypted;
181
182static int ett_collectd;
183static int ett_collectd_string;
184static int ett_collectd_integer;
185static int ett_collectd_part_value;
186static int ett_collectd_value;
187static int ett_collectd_valinfo;
188static int ett_collectd_signature;
189static int ett_collectd_encryption;
190static int ett_collectd_dispatch;
191static int ett_collectd_invalid_length;
192static int ett_collectd_unknown;
193
194static int st_collectd_packets = -1;
195static int st_collectd_values = -1;
196static int st_collectd_values_hosts = -1;
197static int st_collectd_values_plugins = -1;
198static int st_collectd_values_types = -1;
199
200static expert_field ei_collectd_type;
201static expert_field ei_collectd_invalid_length;
202static expert_field ei_collectd_data_valcnt;
203static expert_field ei_collectd_garbage;
204
205/* Prototype for the handoff function */
206void proto_reg_handoff_collectd (void);
207
208static nstime_t
209collectd_time_to_nstime (uint64_t t)
210{
211 nstime_t nstime = NSTIME_INIT_ZERO{0, 0};
212 nstime.secs = (time_t) (t / 1073741824);
213 nstime.nsecs = (int) (((double) (t % 1073741824)) / 1.073741824);
214
215 return (nstime);
216}
217
218static void
219collectd_stats_tree_init (stats_tree *st)
220{
221 st_collectd_packets = stats_tree_create_node (st, "Packets", 0, STAT_DT_INT, false0);
222 st_collectd_values = stats_tree_create_node (st, "Values", 0, STAT_DT_INT, true1);
223
224 st_collectd_values_hosts = stats_tree_create_pivot (st, "By host",
225 st_collectd_values);
226 st_collectd_values_plugins = stats_tree_create_pivot (st, "By plugin",
227 st_collectd_values);
228 st_collectd_values_types = stats_tree_create_pivot (st, "By type",
229 st_collectd_values);
230} /* void collectd_stats_tree_init */
231
232static tap_packet_status
233collectd_stats_tree_packet (stats_tree *st, packet_info *pinfo _U___attribute__((unused)),
234 epan_dissect_t *edt _U___attribute__((unused)), const void *user_data, tap_flags_t flags _U___attribute__((unused)))
235{
236 const tap_data_t *td;
237 string_counter_t *sc;
238
239 td = (const tap_data_t *)user_data;
240 if (td == NULL((void*)0))
241 return (TAP_PACKET_DONT_REDRAW);
242
243 tick_stat_node (st, "Packets", 0, false)(stats_tree_manip_node_int(MN_INCREASE,(st),("Packets"),(0),(
0),1))
;
244 increase_stat_node (st, "Values", 0, true, td->values_num)(stats_tree_manip_node_int(MN_INCREASE,(st),("Values"),(0),(1
),(td->values_num)))
;
245
246 for (sc = td->hosts; sc != NULL((void*)0); sc = sc->next)
247 {
248 int i;
249 for (i = 0; i < sc->count; i++)
250 stats_tree_tick_pivot (st, st_collectd_values_hosts,
251 sc->string);
252 }
253
254 for (sc = td->plugins; sc != NULL((void*)0); sc = sc->next)
255 {
256 int i;
257 for (i = 0; i < sc->count; i++)
258 stats_tree_tick_pivot (st, st_collectd_values_plugins,
259 sc->string);
260 }
261
262 for (sc = td->types; sc != NULL((void*)0); sc = sc->next)
263 {
264 int i;
265 for (i = 0; i < sc->count; i++)
266 stats_tree_tick_pivot (st, st_collectd_values_types,
267 sc->string);
268 }
269
270 return (TAP_PACKET_REDRAW);
271} /* int collectd_stats_tree_packet */
272
273static void
274collectd_stats_tree_register (void)
275{
276 stats_tree_register ("collectd", "collectd", "Collectd", 0,
277 collectd_stats_tree_packet,
278 collectd_stats_tree_init, NULL((void*)0));
279} /* void register_collectd_stat_trees */
280
281static void
282collectd_proto_tree_add_assembled_metric (tvbuff_t *tvb,
283 int offset, int length,
284 value_data_t const *vdispatch, proto_tree *root)
285{
286 proto_item *root_item;
287 proto_tree *subtree;
288 nstime_t nstime;
289
290 subtree = proto_tree_add_subtree(root, tvb, offset + 6, length - 6,
291 ett_collectd_dispatch, &root_item, "Assembled metric");
292 proto_item_set_generated (root_item);
293
294 proto_tree_add_string (subtree, hf_collectd_data_host, tvb,
295 vdispatch->host_off, vdispatch->host_len,
296 STR_NONNULL (vdispatch->host)((vdispatch->host) ? ((const char*)vdispatch->host) : "(null)"
)
);
297
298 proto_tree_add_string (subtree, hf_collectd_data_plugin, tvb,
299 vdispatch->plugin_off, vdispatch->plugin_len,
300 STR_NONNULL (vdispatch->plugin)((vdispatch->plugin) ? ((const char*)vdispatch->plugin)
: "(null)")
);
301
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);
308
309 proto_tree_add_string (subtree, hf_collectd_data_type, tvb,
310 vdispatch->type_off, vdispatch->type_len,
311 STR_NONNULL (vdispatch->type)((vdispatch->type) ? ((const char*)vdispatch->type) : "(null)"
)
);
312
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);
319
320 nstime = collectd_time_to_nstime (vdispatch->time_value);
321 proto_tree_add_time (subtree, hf_collectd_data_time, tvb,
322 vdispatch->time_off, /* length = */ 8, &nstime);
323
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);
327}
328
329static void
330collectd_proto_tree_add_assembled_notification (tvbuff_t *tvb,
331 int offset, int length,
332 notify_data_t const *ndispatch, proto_tree *root)
333{
334 proto_item *root_item;
335 proto_tree *subtree;
336 nstime_t nstime;
337
338 subtree = proto_tree_add_subtree(root, tvb, offset + 6, length - 6,
339 ett_collectd_dispatch, &root_item, "Assembled notification");
340 proto_item_set_generated (root_item);
341
342 proto_tree_add_string (subtree, hf_collectd_data_host, tvb,
343 ndispatch->host_off, ndispatch->host_len,
344 STR_NONNULL (ndispatch->host)((ndispatch->host) ? ((const char*)ndispatch->host) : "(null)"
)
);
345
346 nstime = collectd_time_to_nstime (ndispatch->time_value);
347 proto_tree_add_time (subtree, hf_collectd_data_time, tvb,
348 ndispatch->time_off, /* length = */ 8, &nstime);
349
350 proto_tree_add_uint64 (subtree, hf_collectd_data_severity, tvb,
351 ndispatch->severity_off, /* length = */ 8,
352 ndispatch->severity);
353
354 proto_tree_add_string (subtree, hf_collectd_data_message, tvb,
355 ndispatch->message_off, ndispatch->message_len,
356 ndispatch->message);
357}
358
359static int
360dissect_collectd_string (tvbuff_t *tvb, packet_info *pinfo, int type_hf,
361 int offset, int *ret_offset, int *ret_length,
362 const uint8_t **ret_string, proto_tree *tree_root,
363 proto_item **ret_item)
364{
365 proto_tree *pt;
366 proto_item *pi;
367 int type;
368 int length;
369 int size;
370
371 size = tvb_reported_length_remaining (tvb, offset);
372 if (size < 4)
373 {
374 /* This should never happen, because `dissect_collectd' checks
375 * for this condition already. */
376 return (-1);
377 }
378
379 type = tvb_get_ntohs(tvb, offset);
380 length = tvb_get_ntohs(tvb, offset + 2);
381
382 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
383 ett_collectd_string, &pi, "collectd %s segment: ",
384 val_to_str_const (type, part_names, "UNKNOWN"));
385
386 if (length > size)
387 {
388 proto_item_append_text(pt, "Length = %i <BAD>", length);
389 expert_add_info_format(pinfo, pt, &ei_collectd_invalid_length,
390 "String part with invalid part length: "
391 "Part is longer than rest of package.");
392 return (-1);
393 }
394
395 *ret_offset = offset + 4;
396 *ret_length = length - 4;
397
398 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
399 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
400 proto_tree_add_item_ret_string (pt, type_hf, tvb, *ret_offset, *ret_length, ENC_ASCII0x00000000|ENC_NA0x00000000, pinfo->pool, ret_string);
401
402 proto_item_append_text(pt, "\"%s\"", *ret_string);
403
404 if (ret_item != NULL((void*)0))
405 *ret_item = pi;
406
407 return 0;
408} /* int dissect_collectd_string */
409
410static int
411dissect_collectd_integer (tvbuff_t *tvb, packet_info *pinfo, int type_hf,
412 int offset, int *ret_offset, uint64_t *ret_value,
413 proto_tree *tree_root, proto_item **ret_item)
414{
415 proto_tree *pt;
416 proto_item *pi;
417 int type;
418 int length;
419 int size;
420
421 size = tvb_reported_length_remaining (tvb, offset);
422 if (size < 4)
423 {
424 /* This should never happen, because `dissect_collectd' checks
425 * for this condition already. */
426 return (-1);
427 }
428
429 type = tvb_get_ntohs(tvb, offset);
430 length = tvb_get_ntohs(tvb, offset + 2);
431
432 if (size < 12)
433 {
434 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
435 ett_collectd_integer, NULL((void*)0), "collectd %s segment: <BAD>",
436 val_to_str_const (type, part_names, "UNKNOWN"));
437
438 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2,
439 type);
440 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
441 length);
442 proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
443 "Garbage at end of packet: Length = %i <BAD>",
444 size - 4);
445
446 return (-1);
447 }
448
449 if (length != 12)
450 {
451 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
452 ett_collectd_integer, &pi, "collectd %s segment: <BAD>",
453 val_to_str_const (type, part_names, "UNKNOWN"));
454
455 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2,
456 type);
457 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
458 offset + 2, 2, length);
459 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
460 "Invalid length field for an integer part.");
461
462 return (-1);
463 }
464
465 *ret_offset = offset + 4;
466 *ret_value = tvb_get_ntoh64 (tvb, offset + 4);
467
468 /* Convert the version 4.* time format to the version 5.* time format. */
469 if ((type == TYPE_TIME0x0001) || (type == TYPE_INTERVAL0x0007))
470 *ret_value *= 1073741824;
471
472 /* Create an entry in the protocol tree for this part. The value is
473 * printed depending on the "type" variable: TIME{,_HR} as absolute
474 * time, INTERVAL{,_HR} as relative time, uint64 otherwise. */
475 if ((type == TYPE_TIME0x0001) || (type == TYPE_TIME_HR0x0008))
476 {
477 nstime_t nstime;
478 char *strtime;
479
480 nstime = collectd_time_to_nstime (*ret_value);
481 strtime = abs_time_to_str (pinfo->pool, &nstime, ABSOLUTE_TIME_LOCAL, /* show_zone = */ true)abs_time_to_str_ex(pinfo->pool, &nstime, ABSOLUTE_TIME_LOCAL
, (1) ? (1U << 0) : 0)
;
482 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
483 ett_collectd_integer, &pi, "collectd %s segment: %s",
484 val_to_str_const (type, part_names, "UNKNOWN"),
485 STR_NONNULL (strtime)((strtime) ? ((const char*)strtime) : "(null)"));
486 }
487 else if ((type == TYPE_INTERVAL0x0007) || (type == TYPE_INTERVAL_HR0x0009))
488 {
489 nstime_t nstime;
490 char *strtime;
491
492 nstime = collectd_time_to_nstime (*ret_value);
493 strtime = rel_time_to_str (pinfo->pool, &nstime);
494 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
495 ett_collectd_integer, &pi, "collectd %s segment: %s",
496 val_to_str_const (type, part_names, "UNKNOWN"),
497 strtime);
498 }
499 else
500 {
501 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
502 ett_collectd_integer, &pi, "collectd %s segment: %"PRIu64"l" "u",
503 val_to_str_const (type, part_names, "UNKNOWN"),
504 *ret_value);
505 }
506
507 if (ret_item != NULL((void*)0))
508 *ret_item = pi;
509
510 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
511 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
512 length);
513 if ((type == TYPE_TIME0x0001) || (type == TYPE_INTERVAL0x0007)
514 || (type == TYPE_TIME_HR0x0008) || (type == TYPE_INTERVAL_HR0x0009))
515 {
516 nstime_t nstime;
517
518 nstime = collectd_time_to_nstime (*ret_value);
519 proto_tree_add_time (pt, type_hf, tvb, offset + 4, 8, &nstime);
520 }
521 else
522 {
523 proto_tree_add_item (pt, type_hf, tvb, offset + 4, 8, ENC_BIG_ENDIAN0x00000000);
524 }
525
526 return 0;
527} /* int dissect_collectd_integer */
528
529static void
530dissect_collectd_values(tvbuff_t *tvb, int msg_off, int val_cnt,
531 proto_tree *collectd_tree)
532{
533 proto_tree *values_tree, *value_tree;
534 int i;
535
536 values_tree = proto_tree_add_subtree_format(collectd_tree, tvb, msg_off + 6, val_cnt * 9,
537 ett_collectd_value, NULL((void*)0), "%d value%s", val_cnt,
538 plurality (val_cnt, "", "s")((val_cnt) == 1 ? ("") : ("s")));
539
540 for (i = 0; i < val_cnt; i++)
541 {
542 int value_offset;
543
544 int value_type_offset;
545 uint8_t value_type;
546
547 /* Calculate the offsets of the type byte and the actual value. */
548 value_offset = msg_off + 6
549 + val_cnt /* value types */
550 + (i * 8); /* previous values */
551
552 value_type_offset = msg_off + 6 + i;
553 value_type = tvb_get_uint8 (tvb, value_type_offset);
554
555 switch (value_type) {
556 case TYPE_VALUE_COUNTER0x00:
557 {
558 uint64_t val64;
559
560 val64 = tvb_get_ntoh64 (tvb, value_offset);
561 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
562 val_cnt * 9, ett_collectd_valinfo, NULL((void*)0),
563 "Counter: %"PRIu64"l" "u", val64);
564
565 proto_tree_add_item (value_tree, hf_collectd_val_type,
566 tvb, value_type_offset, 1, ENC_BIG_ENDIAN0x00000000);
567 proto_tree_add_item (value_tree,
568 hf_collectd_val_counter, tvb,
569 value_offset, 8, ENC_BIG_ENDIAN0x00000000);
570 break;
571 }
572
573 case TYPE_VALUE_GAUGE0x01:
574 {
575 double val;
576
577 val = tvb_get_letohieee_double (tvb, value_offset);
578 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
579 val_cnt * 9, ett_collectd_valinfo, NULL((void*)0),
580 "Gauge: %g", val);
581
582 proto_tree_add_item (value_tree, hf_collectd_val_type,
583 tvb, value_type_offset, 1, ENC_BIG_ENDIAN0x00000000);
584 /* Set the `little endian' flag to true here, because
585 * collectd stores doubles in x86 representation. */
586 proto_tree_add_item (value_tree, hf_collectd_val_gauge,
587 tvb, value_offset, 8, ENC_LITTLE_ENDIAN0x80000000);
588 break;
589 }
590
591 case TYPE_VALUE_DERIVE0x02:
592 {
593 int64_t val64;
594
595 val64 = tvb_get_ntoh64 (tvb, value_offset);
596 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
597 val_cnt * 9, ett_collectd_valinfo, NULL((void*)0),
598 "Derive: %"PRIi64"l" "i", val64);
599
600 proto_tree_add_item (value_tree, hf_collectd_val_type,
601 tvb, value_type_offset, 1, ENC_BIG_ENDIAN0x00000000);
602 proto_tree_add_item (value_tree,
603 hf_collectd_val_derive, tvb,
604 value_offset, 8, ENC_BIG_ENDIAN0x00000000);
605 break;
606 }
607
608 case TYPE_VALUE_ABSOLUTE0x03:
609 {
610 uint64_t val64;
611
612 val64 = tvb_get_ntoh64 (tvb, value_offset);
613 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
614 val_cnt * 9, ett_collectd_valinfo, NULL((void*)0),
615 "Absolute: %"PRIu64"l" "u", val64);
616
617 proto_tree_add_item (value_tree, hf_collectd_val_type,
618 tvb, value_type_offset, 1, ENC_BIG_ENDIAN0x00000000);
619 proto_tree_add_item (value_tree,
620 hf_collectd_val_absolute, tvb,
621 value_offset, 8, ENC_BIG_ENDIAN0x00000000);
622 break;
623 }
624
625 default:
626 {
627 uint64_t val64;
628
629 val64 = tvb_get_ntoh64 (tvb, value_offset);
630 value_tree = proto_tree_add_subtree_format(values_tree, tvb, msg_off + 6,
631 val_cnt * 9, ett_collectd_valinfo, NULL((void*)0),
632 "Unknown: %"PRIx64"l" "x",
633 val64);
634
635 proto_tree_add_item (value_tree, hf_collectd_val_type,
636 tvb, value_type_offset, 1, ENC_BIG_ENDIAN0x00000000);
637 proto_tree_add_item (value_tree, hf_collectd_val_unknown,
638 tvb, value_offset, 8, ENC_BIG_ENDIAN0x00000000);
639 break;
640 }
641 } /* switch (value_type) */
642 } /* for (i = 0; i < val_cnt; i++) */
643} /* void dissect_collectd_values */
644
645static int
646dissect_collectd_part_values (tvbuff_t *tvb, packet_info *pinfo, int offset,
647 value_data_t *vdispatch, proto_tree *tree_root)
648{
649 proto_tree *pt;
650 proto_item *pi;
651 int type;
652 int length;
653 int size;
654 int values_count;
655 int corrected_values_count;
656
657 size = tvb_reported_length_remaining (tvb, offset);
658 if (size < 4)
659 {
660 /* This should never happen, because `dissect_collectd' checks
661 * for this condition already. */
662 return (-1);
663 }
664
665 type = tvb_get_ntohs (tvb, offset);
666 length = tvb_get_ntohs (tvb, offset + 2);
667
668 if (size < 15)
669 {
670 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
671 ett_collectd_part_value, NULL((void*)0), "collectd %s segment: <BAD>",
672 val_to_str_const (type, part_names, "UNKNOWN"));
673
674 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
675 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
676 length);
677 proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
678 "Garbage at end of packet: Length = %i <BAD>",
679 size - 4);
680 return (-1);
681 }
682
683 if ((length < 15) || ((length % 9) != 6))
684 {
685 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
686 ett_collectd_part_value, &pi, "collectd %s segment: <BAD>",
687 val_to_str_const (type, part_names, "UNKNOWN"));
688
689 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
690 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
691 offset + 2, 2, length);
692 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
693 "Invalid length field for a values part.");
694
695 return (-1);
696 }
697
698 values_count = tvb_get_ntohs (tvb, offset + 4);
699 corrected_values_count = (length - 6) / 9;
700
701 if (values_count != corrected_values_count)
702 {
703 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
704 ett_collectd_part_value, NULL((void*)0),
705 "collectd %s segment: %d (%d) value%s <BAD>",
706 val_to_str_const (type, part_names, "UNKNOWN"),
707 values_count, corrected_values_count,
708 plurality(values_count, "", "s")((values_count) == 1 ? ("") : ("s")));
709 }
710 else
711 {
712 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
713 ett_collectd_part_value, NULL((void*)0),
714 "collectd %s segment: %d value%s",
715 val_to_str_const (type, part_names, "UNKNOWN"),
716 values_count,
717 plurality(values_count, "", "s")((values_count) == 1 ? ("") : ("s")));
718 }
719
720 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
721 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
722
723 pi = proto_tree_add_item (pt, hf_collectd_data_valcnt, tvb,
724 offset + 4, 2, ENC_BIG_ENDIAN0x00000000);
725 if (values_count != corrected_values_count)
726 expert_add_info(pinfo, pi, &ei_collectd_data_valcnt);
727
728 values_count = corrected_values_count;
729
730 dissect_collectd_values (tvb, offset, values_count, pt);
731 collectd_proto_tree_add_assembled_metric (tvb, offset + 6, length - 6,
732 vdispatch, pt);
733
734 return 0;
735} /* void dissect_collectd_part_values */
736
737static int
738dissect_collectd_signature (tvbuff_t *tvb, packet_info *pinfo,
739 int offset, proto_tree *tree_root)
740{
741 proto_item *pi;
742 proto_tree *pt;
743 int type;
744 int length;
745 int size;
746
747 size = tvb_reported_length_remaining (tvb, offset);
748 if (size < 4)
749 {
750 /* This should never happen, because `dissect_collectd' checks
751 * for this condition already. */
752 return (-1);
753 }
754
755 type = tvb_get_ntohs (tvb, offset);
756 length = tvb_get_ntohs (tvb, offset + 2);
757
758 if (size < 36) /* remaining packet size too small for signature */
759 {
760 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
761 ett_collectd_signature, NULL((void*)0), "collectd %s segment: <BAD>",
762 val_to_str_const (type, part_names, "UNKNOWN"));
763
764 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
765 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
766 length);
767 proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
768 "Garbage at end of packet: Length = %i <BAD>",
769 size - 4);
770 return (-1);
771 }
772
773 if (length < 36)
774 {
775 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
776 ett_collectd_signature, NULL((void*)0), "collectd %s segment: <BAD>",
777 val_to_str_const (type, part_names, "UNKNOWN"));
778
779 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
780 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
781 offset + 2, 2, length);
782 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
783 "Invalid length field for a signature part.");
784
785 return (-1);
786 }
787
788 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
789 ett_collectd_signature, NULL((void*)0), "collectd %s segment: HMAC-SHA-256",
790 val_to_str_const (type, part_names, "UNKNOWN"));
791
792 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
793 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
794 length);
795 proto_tree_add_item (pt, hf_collectd_data_sighash, tvb, offset + 4, 32, ENC_NA0x00000000);
796 proto_tree_add_item (pt, hf_collectd_data_username, tvb, offset + 36, length - 36, ENC_ASCII0x00000000);
797
798 return 0;
799} /* int dissect_collectd_signature */
800
801static int
802dissect_collectd_encrypted (tvbuff_t *tvb, packet_info *pinfo,
803 int offset, proto_tree *tree_root)
804{
805 proto_item *pi;
806 proto_tree *pt;
807 int type;
808 int length;
809 int size;
810 int username_length;
811
812 size = tvb_reported_length_remaining (tvb, offset);
813 if (size < 4)
814 {
815 /* This should never happen, because `dissect_collectd' checks
816 * for this condition already. */
817 return (-1);
818 }
819
820 type = tvb_get_ntohs (tvb, offset);
821 length = tvb_get_ntohs (tvb, offset + 2);
822
823 if (size < 42) /* remaining packet size too small for signature */
824 {
825 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
826 ett_collectd_encryption, NULL((void*)0), "collectd %s segment: <BAD>",
827 val_to_str_const (type, part_names, "UNKNOWN"));
828
829 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
830 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2,
831 length);
832 proto_tree_add_expert_format(pt, pinfo, &ei_collectd_garbage, tvb, offset + 4, -1,
833 "Garbage at end of packet: Length = %i <BAD>",
834 size - 4);
835 return (-1);
836 }
837
838 if (length < 42)
839 {
840 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
841 ett_collectd_encryption, NULL((void*)0), "collectd %s segment: <BAD>",
842 val_to_str_const (type, part_names, "UNKNOWN"));
843
844 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
845 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
846 offset + 2, 2, length);
847 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
848 "Invalid length field for an encryption part.");
849
850 return (-1);
851 }
852
853 username_length = tvb_get_ntohs (tvb, offset + 4);
854 if (username_length > (length - 42))
855 {
856 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, -1,
857 ett_collectd_encryption, NULL((void*)0), "collectd %s segment: <BAD>",
858 val_to_str_const (type, part_names, "UNKNOWN"));
859
860 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
861 proto_tree_add_uint (pt, hf_collectd_length, tvb,
862 offset + 2, 2, length);
863 pi = proto_tree_add_uint (pt, hf_collectd_data_username_len, tvb,
864 offset + 4, 2, length);
865 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
866 "Invalid username length field for an encryption part.");
867
868 return (-1);
869 }
870
871 pt = proto_tree_add_subtree_format(tree_root, tvb, offset, length,
872 ett_collectd_encryption, NULL((void*)0), "collectd %s segment: AES-256",
873 val_to_str_const (type, part_names, "UNKNOWN"));
874
875 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset, 2, type);
876 proto_tree_add_uint (pt, hf_collectd_length, tvb, offset + 2, 2, length);
877 proto_tree_add_uint (pt, hf_collectd_data_username_len, tvb, offset + 4, 2, username_length);
878 proto_tree_add_item (pt, hf_collectd_data_username, tvb, offset + 6, username_length, ENC_ASCII0x00000000);
879 proto_tree_add_item (pt, hf_collectd_data_initvec, tvb,
880 offset + (6 + username_length), 16, ENC_NA0x00000000);
881 proto_tree_add_item (pt, hf_collectd_data_encrypted, tvb,
882 offset + (22 + username_length),
883 length - (22 + username_length), ENC_NA0x00000000);
884
885 return 0;
886} /* int dissect_collectd_encrypted */
887
888static int
889stats_account_string (wmem_allocator_t *scope, string_counter_t **ret_list, const char *new_value)
890{
891 string_counter_t *entry;
892
893 if (ret_list == NULL((void*)0))
894 return (-1);
895
896 if (new_value == NULL((void*)0))
897 new_value = "(null)";
898
899 for (entry = *ret_list; entry != NULL((void*)0); entry = entry->next)
900 if (strcmp (new_value, entry->string) == 0)
901 {
902 entry->count++;
903 return 0;
904 }
905
906 entry = (string_counter_t *)wmem_alloc0 (scope, sizeof (*entry));
907 entry->string = wmem_strdup (scope, new_value);
908 entry->count = 1;
909 entry->next = *ret_list;
910
911 *ret_list = entry;
912
913 return 0;
914}
915
916static int
917dissect_collectd_parts(tvbuff_t *tvb, packet_info *pinfo, proto_tree *collectd_tree, void* data _U___attribute__((unused)))
918{
919 int offset;
920 int size;
921 value_data_t vdispatch;
922 notify_data_t ndispatch;
923 int status;
924 proto_item *pi;
2
'pi' declared without an initial value
925 proto_tree *pt;
926
927 memset(&vdispatch, '\0', sizeof(vdispatch));
928 memset(&ndispatch, '\0', sizeof(ndispatch));
929
930 tap_data_t *tap_data = p_get_proto_data(pinfo->pool, pinfo, proto_collectd, TAP_DATA_KEY0);
931 column_data_t *col_data = p_get_proto_data(pinfo->pool, pinfo, proto_collectd, COL_DATA_KEY1);
932
933 offset = 0;
934 size = tvb_reported_length(tvb);
935
936 status = 0;
937 while ((size > 0) && (status == 0))
3
Assuming 'size' is > 0
4
Loop condition is true. Entering loop body
938 {
939 int part_type;
940 int part_length;
941
942 /* Check if there are at least four bytes left first.
943 * Four bytes are used to read the type and the length
944 * of the next part. If there's less, there's some garbage
945 * at the end of the packet. */
946 if (size < 4)
5
Assuming 'size' is < 4
6
Taking true branch
947 {
948 proto_tree_add_expert_format(pi, pinfo, &ei_collectd_garbage, tvb,
7
1st function call argument is an uninitialized value
949 offset, -1,
950 "Garbage at end of packet: Length = %i <BAD>",
951 size);
952 col_data->pkt_errors++;
953 break;
954 }
955
956 /* dissect a message entry */
957 part_type = tvb_get_ntohs (tvb, offset);
958 part_length = tvb_get_ntohs (tvb, offset + 2);
959
960 /* Check if the length of the part is in the valid range. Don't
961 * confuse this with the above: Here we check the information
962 * provided in the packet.. */
963 if ((part_length < 4) || (part_length > size))
964 {
965 pt = proto_tree_add_subtree_format(collectd_tree, tvb,
966 offset, part_length, ett_collectd_invalid_length, NULL((void*)0),
967 "collectd %s segment: Length = %i <BAD>",
968 val_to_str_const (part_type, part_names, "UNKNOWN"),
969 part_length);
970
971 proto_tree_add_uint (pt, hf_collectd_type, tvb, offset,
972 2, part_type);
973 pi = proto_tree_add_uint (pt, hf_collectd_length, tvb,
974 offset + 2, 2, part_length);
975
976 if (part_length < 4)
977 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
978 "Bad part length: Is %i, expected at least 4",
979 part_length);
980 else
981 expert_add_info_format(pinfo, pi, &ei_collectd_invalid_length,
982 "Bad part length: Larger than remaining packet size.");
983
984 col_data->pkt_errors++;
985 break;
986 }
987
988 /* The header information looks okay, let's tend to the actual
989 * payload in this part. */
990 switch (part_type) {
991 case TYPE_HOST0x0000:
992 {
993 status = dissect_collectd_string (tvb, pinfo,
994 hf_collectd_data_host,
995 offset,
996 &vdispatch.host_off,
997 &vdispatch.host_len,
998 &vdispatch.host,
999 collectd_tree, /* item = */ NULL((void*)0));
1000 if (status != 0)
1001 col_data->pkt_errors++;
1002 else
1003 {
1004 if (col_data->pkt_host == NULL((void*)0))
1005 col_data->pkt_host = vdispatch.host;
1006 ndispatch.host_off = vdispatch.host_off;
1007 ndispatch.host_len = vdispatch.host_len;
1008 ndispatch.host = vdispatch.host;
1009 }
1010
1011 break;
1012 }
1013
1014 case TYPE_PLUGIN0x0002:
1015 {
1016 status = dissect_collectd_string (tvb, pinfo,
1017 hf_collectd_data_plugin,
1018 offset,
1019 &vdispatch.plugin_off,
1020 &vdispatch.plugin_len,
1021 &vdispatch.plugin,
1022 collectd_tree, /* item = */ NULL((void*)0));
1023 if (status != 0)
1024 col_data->pkt_errors++;
1025 else
1026 col_data->pkt_plugins++;
1027
1028 break;
1029 }
1030
1031 case TYPE_PLUGIN_INSTANCE0x0003:
1032 {
1033 status = dissect_collectd_string (tvb, pinfo,
1034 hf_collectd_data_plugin_inst,
1035 offset,
1036 &vdispatch.plugin_instance_off,
1037 &vdispatch.plugin_instance_len,
1038 &vdispatch.plugin_instance,
1039 collectd_tree, /* item = */ NULL((void*)0));
1040 if (status != 0)
1041 col_data->pkt_errors++;
1042
1043 break;
1044 }
1045
1046 case TYPE_TYPE0x0004:
1047 {
1048 status = dissect_collectd_string (tvb, pinfo,
1049 hf_collectd_data_type,
1050 offset,
1051 &vdispatch.type_off,
1052 &vdispatch.type_len,
1053 &vdispatch.type,
1054 collectd_tree, /* item = */ NULL((void*)0));
1055 if (status != 0)
1056 col_data->pkt_errors++;
1057
1058 break;
1059 }
1060
1061 case TYPE_TYPE_INSTANCE0x0005:
1062 {
1063 status = dissect_collectd_string (tvb, pinfo,
1064 hf_collectd_data_type_inst,
1065 offset,
1066 &vdispatch.type_instance_off,
1067 &vdispatch.type_instance_len,
1068 &vdispatch.type_instance,
1069 collectd_tree, /* item = */ NULL((void*)0));
1070 if (status != 0)
1071 col_data->pkt_errors++;
1072
1073 break;
1074 }
1075
1076 case TYPE_TIME0x0001:
1077 case TYPE_TIME_HR0x0008:
1078 {
1079 pi = NULL((void*)0);
1080 status = dissect_collectd_integer (tvb, pinfo,
1081 hf_collectd_data_time,
1082 offset,
1083 &vdispatch.time_off,
1084 &vdispatch.time_value,
1085 collectd_tree, &pi);
1086 if (status != 0)
1087 col_data->pkt_errors++;
1088
1089 break;
1090 }
1091
1092 case TYPE_INTERVAL0x0007:
1093 case TYPE_INTERVAL_HR0x0009:
1094 {
1095 status = dissect_collectd_integer (tvb, pinfo,
1096 hf_collectd_data_interval,
1097 offset,
1098 &vdispatch.interval_off,
1099 &vdispatch.interval,
1100 collectd_tree, /* item = */ NULL((void*)0));
1101 if (status != 0)
1102 col_data->pkt_errors++;
1103
1104 break;
1105 }
1106
1107 case TYPE_VALUES0x0006:
1108 {
1109 status = dissect_collectd_part_values (tvb, pinfo,
1110 offset,
1111 &vdispatch,
1112 collectd_tree);
1113 if (status != 0)
1114 col_data->pkt_errors++;
1115 else
1116 col_data->pkt_values++;
1117
1118 tap_data->values_num++;
1119 stats_account_string (pinfo->pool,
1120 &tap_data->hosts,
1121 vdispatch.host);
1122 stats_account_string (pinfo->pool,
1123 &tap_data->plugins,
1124 vdispatch.plugin);
1125 stats_account_string (pinfo->pool,
1126 &tap_data->types,
1127 vdispatch.type);
1128
1129 break;
1130 }
1131
1132 case TYPE_MESSAGE0x0100:
1133 {
1134 pi = NULL((void*)0);
1135 status = dissect_collectd_string (tvb, pinfo,
1136 hf_collectd_data_message,
1137 offset,
1138 &ndispatch.message_off,
1139 &ndispatch.message_len,
1140 &ndispatch.message,
1141 collectd_tree, &pi);
1142 if (status != 0)
1143 {
1144 col_data->pkt_errors++;
1145 break;
1146 }
1147 col_data->pkt_messages++;
1148
1149 pt = proto_item_get_subtree (pi);
1150
1151 collectd_proto_tree_add_assembled_notification (tvb,
1152 offset + 4, part_length - 1,
1153 &ndispatch, pt);
1154
1155 break;
1156 }
1157
1158 case TYPE_SEVERITY0x0101:
1159 {
1160 pi = NULL((void*)0);
1161 status = dissect_collectd_integer (tvb, pinfo,
1162 hf_collectd_data_severity,
1163 offset,
1164 &ndispatch.severity_off,
1165 &ndispatch.severity,
1166 collectd_tree, &pi);
1167 if (status != 0)
1168 col_data->pkt_errors++;
1169 else
1170 {
1171 proto_item_set_text (pi,
1172 "collectd SEVERITY segment: "
1173 "%s (%"PRIu64"l" "u"")",
1174 val64_to_str_const (ndispatch.severity, severity_names, "UNKNOWN"),
1175 ndispatch.severity);
1176 }
1177
1178 break;
1179 }
1180
1181 case TYPE_SIGN_SHA2560x0200:
1182 {
1183 status = dissect_collectd_signature (tvb, pinfo,
1184 offset,
1185 collectd_tree);
1186 if (status != 0)
1187 col_data->pkt_errors++;
1188
1189 break;
1190 }
1191
1192 case TYPE_ENCR_AES2560x0210:
1193 {
1194 status = dissect_collectd_encrypted (tvb, pinfo,
1195 offset, collectd_tree);
1196 if (status != 0)
1197 col_data->pkt_errors++;
1198
1199 break;
1200 }
1201
1202 default:
1203 {
1204 col_data->pkt_unknown++;
1205 pt = proto_tree_add_subtree_format(collectd_tree, tvb,
1206 offset, part_length, ett_collectd_unknown, NULL((void*)0),
1207 "collectd %s segment: %i bytes",
1208 val_to_str_const(part_type, part_names, "UNKNOWN"),
1209 part_length);
1210
1211 pi = proto_tree_add_uint (pt, hf_collectd_type, tvb,
1212 offset, 2, part_type);
1213 proto_tree_add_uint (pt, hf_collectd_length, tvb,
1214 offset + 2, 2, part_length);
1215 proto_tree_add_item (pt, hf_collectd_data, tvb,
1216 offset + 4, part_length - 4, ENC_NA0x00000000);
1217
1218 expert_add_info_format(pinfo, pi, &ei_collectd_type,
1219 "Unknown part type %#x. Cannot decode data.",
1220 part_type);
1221 }
1222 } /* switch (part_type) */
1223
1224 offset += part_length;
1225 size -= part_length;
1226 } /* while ((size > 4) && (status == 0)) */
1227
1228 return tvb_captured_length(tvb);
1229}
1230
1231static int
1232dissect_collectd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U___attribute__((unused)))
1233{
1234 proto_item *pi;
1235 proto_tree *collectd_tree;
1236
1237 col_set_str(pinfo->cinfo, COL_PROTOCOL, "collectd");
1238 col_clear(pinfo->cinfo, COL_INFO);
1239
1240 tap_data_t *tap_data = wmem_new0(pinfo->pool, tap_data_t)((tap_data_t*)wmem_alloc0((pinfo->pool), sizeof(tap_data_t
)))
;
1241 p_add_proto_data(pinfo->pool, pinfo, proto_collectd, TAP_DATA_KEY0, tap_data);
1242
1243 column_data_t *col_data = wmem_new0(pinfo->pool, column_data_t)((column_data_t*)wmem_alloc0((pinfo->pool), sizeof(column_data_t
)))
;
1244 p_add_proto_data(pinfo->pool, pinfo, proto_collectd, COL_DATA_KEY1, col_data);
1245
1246 /* create the collectd protocol tree */
1247 pi = proto_tree_add_item(tree, proto_collectd, tvb, 0, -1, ENC_NA0x00000000);
1248 collectd_tree = proto_item_add_subtree(pi, ett_collectd);
1249
1250 dissect_collectd_parts(tvb, pinfo, collectd_tree, data);
1
Calling 'dissect_collectd_parts'
1251
1252 /* Put summary information in columns */
1253 col_add_fstr(pinfo->cinfo, COL_INFO, "Host=%s, %2d value%s for %d plugin%s %d message%s",
1254 col_data->pkt_host,
1255 col_data->pkt_values, plurality(col_data->pkt_values, " ", "s")((col_data->pkt_values) == 1 ? (" ") : ("s")),
1256 col_data->pkt_plugins, plurality(col_data->pkt_plugins, ", ", "s,")((col_data->pkt_plugins) == 1 ? (", ") : ("s,")),
1257 col_data->pkt_messages, plurality(col_data->pkt_messages, ", ", "s")((col_data->pkt_messages) == 1 ? (", ") : ("s")));
1258
1259 if (col_data->pkt_unknown) {
1260 col_append_fstr(pinfo->cinfo, COL_INFO, ", %d unknown",
1261 col_data->pkt_unknown);
1262 }
1263
1264 if (col_data->pkt_errors) {
1265 col_add_fstr(pinfo->cinfo, COL_INFO, ", %d error%s",
1266 col_data->pkt_errors, plurality(col_data->pkt_errors, "", "s")((col_data->pkt_errors) == 1 ? ("") : ("s")));
1267 }
1268
1269 /* Dispatch tap data. */
1270 tap_queue_packet(tap_collectd, pinfo, tap_data);
1271
1272 return tvb_captured_length(tvb);
1273} /* void dissect_collectd */
1274
1275void proto_register_collectd(void)
1276{
1277 expert_module_t* expert_collectd;
1278
1279 /* Setup list of header fields */
1280 static hf_register_info hf[] = {
1281 { &hf_collectd_type,
1282 { "Type", "collectd.type", FT_UINT16, BASE_HEX,
1283 VALS(part_names)((0 ? (const struct _value_string*)0 : ((part_names)))), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1284 },
1285 { &hf_collectd_length,
1286 { "Length", "collectd.len", FT_UINT16, BASE_DEC,
1287 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1288 },
1289 { &hf_collectd_data,
1290 { "Payload", "collectd.data", FT_BYTES, BASE_NONE,
1291 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1292 },
1293 { &hf_collectd_data_host,
1294 { "Host name", "collectd.data.host", FT_STRING, BASE_NONE,
1295 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1296 },
1297 { &hf_collectd_data_interval,
1298 { "Interval", "collectd.data.interval", FT_RELATIVE_TIME, BASE_NONE,
1299 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1300 },
1301 { &hf_collectd_data_time,
1302 { "Timestamp", "collectd.data.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
1303 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1304 },
1305 { &hf_collectd_data_plugin,
1306 { "Plugin", "collectd.data.plugin", FT_STRING, BASE_NONE,
1307 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1308 },
1309 { &hf_collectd_data_plugin_inst,
1310 { "Plugin instance", "collectd.data.plugin.inst", FT_STRING, BASE_NONE,
1311 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1312 },
1313 { &hf_collectd_data_type,
1314 { "Type", "collectd.data.type", FT_STRING, BASE_NONE,
1315 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1316 },
1317 { &hf_collectd_data_type_inst,
1318 { "Type instance", "collectd.data.type.inst", FT_STRING, BASE_NONE,
1319 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1320 },
1321 { &hf_collectd_data_valcnt,
1322 { "Value count", "collectd.data.valcnt", FT_UINT16, BASE_DEC,
1323 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1324 },
1325 { &hf_collectd_val_type,
1326 { "Value type", "collectd.val.type", FT_UINT8, BASE_HEX,
1327 VALS(valuetypenames)((0 ? (const struct _value_string*)0 : ((valuetypenames)))), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1328 },
1329 { &hf_collectd_val_counter,
1330 { "Counter value", "collectd.val.counter", FT_UINT64, BASE_DEC,
1331 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1332 },
1333 { &hf_collectd_val_gauge,
1334 { "Gauge value", "collectd.val.gauge", FT_DOUBLE, BASE_NONE,
1335 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1336 },
1337 { &hf_collectd_val_derive,
1338 { "Derive value", "collectd.val.derive", FT_INT64, BASE_DEC,
1339 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1340 },
1341 { &hf_collectd_val_absolute,
1342 { "Absolute value", "collectd.val.absolute", FT_UINT64, BASE_DEC,
1343 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1344 },
1345 { &hf_collectd_val_unknown,
1346 { "Value of unknown type", "collectd.val.unknown", FT_UINT64, BASE_HEX,
1347 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1348 },
1349 { &hf_collectd_data_severity,
1350 { "Severity", "collectd.data.severity", FT_UINT64, BASE_HEX | BASE_VAL64_STRING0x00000400,
1351 VALS64(severity_names)((0 ? (const struct _val64_string*)0 : ((severity_names)))),
1352 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1353 },
1354 { &hf_collectd_data_message,
1355 { "Message", "collectd.data.message", FT_STRING, BASE_NONE,
1356 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1357 },
1358 { &hf_collectd_data_sighash,
1359 { "Signature", "collectd.data.sighash", FT_BYTES, BASE_NONE,
1360 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1361 },
1362 { &hf_collectd_data_initvec,
1363 { "Init vector", "collectd.data.initvec", FT_BYTES, BASE_NONE,
1364 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1365 },
1366 { &hf_collectd_data_username_len,
1367 { "Username length", "collectd.data.username_length", FT_UINT16, BASE_DEC,
1368 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1369 },
1370 { &hf_collectd_data_username,
1371 { "Username", "collectd.data.username", FT_STRING, BASE_NONE,
1372 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1373 },
1374 { &hf_collectd_data_encrypted,
1375 { "Encrypted data", "collectd.data.encrypted", FT_BYTES, BASE_NONE,
1376 NULL((void*)0), 0x0, NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
1377 },
1378 };
1379
1380 /* Setup protocol subtree array */
1381 static int *ett[] = {
1382 &ett_collectd,
1383 &ett_collectd_string,
1384 &ett_collectd_integer,
1385 &ett_collectd_part_value,
1386 &ett_collectd_value,
1387 &ett_collectd_valinfo,
1388 &ett_collectd_signature,
1389 &ett_collectd_encryption,
1390 &ett_collectd_dispatch,
1391 &ett_collectd_invalid_length,
1392 &ett_collectd_unknown,
1393 };
1394
1395 static ei_register_info ei[] = {
1396 { &ei_collectd_invalid_length, { "collectd.invalid_length", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "Invalid length", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE
, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void
*)0)}}
}},
1397 { &ei_collectd_garbage, { "collectd.garbage", PI_MALFORMED0x07000000, PI_ERROR0x00800000, "Garbage at end of packet", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE
, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void
*)0)}}
}},
1398 { &ei_collectd_data_valcnt, { "collectd.data.valcnt.mismatch", PI_MALFORMED0x07000000, PI_WARN0x00600000, "Number of values and length of part do not match. Assuming length is correct.", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE
, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void
*)0)}}
}},
1399 { &ei_collectd_type, { "collectd.type.unknown", PI_UNDECODED0x05000000, PI_NOTE0x00400000, "Unknown part type", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE
, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void
*)0)}}
}},
1400 };
1401
1402 /* Register the protocol name and description */
1403 proto_collectd = proto_register_protocol("collectd network data", "collectd", "collectd");
1404
1405 /* Required function calls to register the header fields and subtrees used */
1406 proto_register_field_array(proto_collectd, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
1407 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
1408 expert_collectd = expert_register_protocol(proto_collectd);
1409 expert_register_field_array(expert_collectd, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
1410
1411 tap_collectd = register_tap ("collectd");
1412
1413 collectd_handle = register_dissector("collectd", dissect_collectd, proto_collectd);
1414}
1415
1416void proto_reg_handoff_collectd (void)
1417{
1418 dissector_add_uint_with_preference("udp.port", UDP_PORT_COLLECTD25826, collectd_handle);
1419
1420 collectd_stats_tree_register ();
1421} /* void proto_reg_handoff_collectd */
1422
1423/*
1424 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1425 *
1426 * Local variables:
1427 * c-basic-offset: 8
1428 * tab-width: 8
1429 * indent-tabs-mode: t
1430 * End:
1431 *
1432 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1433 * :indentSize=8:tabSize=8:noTabs=false:
1434 */