2009-09-14 01:36:26 +00:00
/* packet-collectd.c
* Routines for collectd ( http : //collectd.org/) network plugin dissection
*
* Copyright 2008 Bruno Premont < bonbons at linux - vserver . org >
2013-05-17 00:06:26 +00:00
* Copyright 2009 - 2013 Florian Forster < octo at collectd . org >
2009-09-14 01:36:26 +00:00
*
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
* Copyright 1998 Gerald Combs
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2012-06-28 22:56:06 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
2009-09-14 01:36:26 +00:00
*/
2012-09-20 02:03:38 +00:00
# include "config.h"
2009-09-14 01:36:26 +00:00
# include <string.h>
# include <glib.h>
# include <epan/packet.h>
# include <epan/prefs.h>
# include <epan/expert.h>
2009-09-15 01:34:01 +00:00
# include <epan/stats_tree.h>
2013-09-13 17:25:54 +00:00
# include <epan/wmem/wmem.h>
2013-12-21 17:23:17 +00:00
# include <epan/to_str.h>
2009-09-14 01:36:26 +00:00
2013-05-17 00:06:26 +00:00
# define STR_NONNULL(str) ((str) ? (str) : "(null)")
2009-09-14 01:36:26 +00:00
# define TYPE_HOST 0x0000
# define TYPE_TIME 0x0001
2013-05-17 00:06:26 +00:00
# define TYPE_TIME_HR 0x0008
2009-09-14 01:36:26 +00:00
# define TYPE_PLUGIN 0x0002
# define TYPE_PLUGIN_INSTANCE 0x0003
# define TYPE_TYPE 0x0004
# define TYPE_TYPE_INSTANCE 0x0005
# define TYPE_VALUES 0x0006
# define TYPE_INTERVAL 0x0007
2013-05-17 00:06:26 +00:00
# define TYPE_INTERVAL_HR 0x0009
2009-09-14 01:36:26 +00:00
# define TYPE_MESSAGE 0x0100
# define TYPE_SEVERITY 0x0101
2009-09-15 00:18:40 +00:00
# define TYPE_SIGN_SHA256 0x0200
# define TYPE_ENCR_AES256 0x0210
2009-09-14 01:36:26 +00:00
2013-03-15 22:40:15 +00:00
void proto_register_collectd ( void ) ;
2009-09-14 01:36:26 +00:00
typedef struct value_data_s {
gchar * host ;
gint host_off ;
gint host_len ;
guint64 time ;
gint time_off ;
guint64 interval ;
gint interval_off ;
gchar * plugin ;
gint plugin_off ;
gint plugin_len ;
gchar * plugin_instance ;
gint plugin_instance_off ;
gint plugin_instance_len ;
gchar * type ;
gint type_off ;
gint type_len ;
gchar * type_instance ;
gint type_instance_off ;
gint type_instance_len ;
} value_data_t ;
typedef struct notify_data_s {
gchar * host ;
gint host_off ;
gint host_len ;
guint64 time ;
gint time_off ;
guint64 severity ;
gint severity_off ;
gchar * message ;
gint message_off ;
gint message_len ;
} notify_data_t ;
2009-09-15 01:34:01 +00:00
struct string_counter_s ;
typedef struct string_counter_s string_counter_t ;
struct string_counter_s
{
2012-12-26 05:57:06 +00:00
const gchar * string ;
2009-09-15 01:34:01 +00:00
gint count ;
string_counter_t * next ;
} ;
typedef struct tap_data_s {
gint values_num ;
string_counter_t * hosts ;
string_counter_t * plugins ;
string_counter_t * types ;
} tap_data_t ;
2009-09-14 01:36:26 +00:00
static const value_string part_names [ ] = {
{ TYPE_VALUES , " VALUES " } ,
{ TYPE_TIME , " TIME " } ,
2013-05-17 00:06:26 +00:00
{ TYPE_TIME_HR , " TIME_HR " } ,
2009-09-14 01:36:26 +00:00
{ TYPE_INTERVAL , " INTERVAL " } ,
2013-05-17 00:06:26 +00:00
{ TYPE_INTERVAL_HR , " INTERVAL_HR " } ,
2009-09-14 01:36:26 +00:00
{ TYPE_HOST , " HOST " } ,
{ TYPE_PLUGIN , " PLUGIN " } ,
{ TYPE_PLUGIN_INSTANCE , " PLUGIN_INSTANCE " } ,
{ TYPE_TYPE , " TYPE " } ,
{ TYPE_TYPE_INSTANCE , " TYPE_INSTANCE " } ,
{ TYPE_MESSAGE , " MESSAGE " } ,
{ TYPE_SEVERITY , " SEVERITY " } ,
2009-09-15 00:18:40 +00:00
{ TYPE_SIGN_SHA256 , " SIGNATURE " } ,
{ TYPE_ENCR_AES256 , " ENCRYPTED_DATA " } ,
2009-09-14 01:36:26 +00:00
{ 0 , NULL }
} ;
# define TYPE_VALUE_COUNTER 0x00
# define TYPE_VALUE_GAUGE 0x01
2009-09-16 19:02:51 +00:00
# define TYPE_VALUE_DERIVE 0x02
# define TYPE_VALUE_ABSOLUTE 0x03
2009-09-14 01:36:26 +00:00
static const value_string valuetypenames [ ] = {
{ TYPE_VALUE_COUNTER , " COUNTER " } ,
{ TYPE_VALUE_GAUGE , " GAUGE " } ,
2009-09-16 19:02:51 +00:00
{ TYPE_VALUE_DERIVE , " DERIVE " } ,
{ TYPE_VALUE_ABSOLUTE , " ABSOLUTE " } ,
2009-09-14 01:36:26 +00:00
{ 0 , NULL }
} ;
# define SEVERITY_FAILURE 0x01
# define SEVERITY_WARNING 0x02
# define SEVERITY_OKAY 0x04
2013-07-26 21:51:39 +00:00
static const val64_string severity_names [ ] = {
2009-09-14 01:36:26 +00:00
{ SEVERITY_FAILURE , " FAILURE " } ,
{ SEVERITY_WARNING , " WARNING " } ,
{ SEVERITY_OKAY , " OKAY " } ,
{ 0 , NULL }
} ;
# define UDP_PORT_COLLECTD 25826
2009-10-18 21:13:17 +00:00
static guint collectd_udp_port = UDP_PORT_COLLECTD ;
2009-09-14 01:36:26 +00:00
static gint proto_collectd = - 1 ;
2009-09-15 01:34:01 +00:00
static gint tap_collectd = - 1 ;
2009-09-14 01:36:26 +00:00
static gint hf_collectd_type = - 1 ;
static gint hf_collectd_length = - 1 ;
static gint hf_collectd_data = - 1 ;
static gint hf_collectd_data_host = - 1 ;
static gint hf_collectd_data_time = - 1 ;
static gint hf_collectd_data_interval = - 1 ;
static gint hf_collectd_data_plugin = - 1 ;
static gint hf_collectd_data_plugin_inst = - 1 ;
static gint hf_collectd_data_type = - 1 ;
static gint hf_collectd_data_type_inst = - 1 ;
static gint hf_collectd_data_valcnt = - 1 ;
static gint hf_collectd_val_type = - 1 ;
static gint hf_collectd_val_counter = - 1 ;
static gint hf_collectd_val_gauge = - 1 ;
2009-09-16 19:02:51 +00:00
static gint hf_collectd_val_derive = - 1 ;
static gint hf_collectd_val_absolute = - 1 ;
2009-09-14 01:36:26 +00:00
static gint hf_collectd_val_unknown = - 1 ;
static gint hf_collectd_data_severity = - 1 ;
static gint hf_collectd_data_message = - 1 ;
2009-09-15 00:18:40 +00:00
static gint hf_collectd_data_sighash = - 1 ;
static gint hf_collectd_data_initvec = - 1 ;
static gint hf_collectd_data_username_len = - 1 ;
static gint hf_collectd_data_username = - 1 ;
static gint hf_collectd_data_encrypted = - 1 ;
2009-09-14 01:36:26 +00:00
static gint ett_collectd = - 1 ;
static gint ett_collectd_string = - 1 ;
static gint ett_collectd_integer = - 1 ;
static gint ett_collectd_part_value = - 1 ;
static gint ett_collectd_value = - 1 ;
static gint ett_collectd_valinfo = - 1 ;
2009-09-15 00:18:40 +00:00
static gint ett_collectd_signature = - 1 ;
static gint ett_collectd_encryption = - 1 ;
2009-09-14 01:36:26 +00:00
static gint ett_collectd_dispatch = - 1 ;
static gint ett_collectd_invalid_length = - 1 ;
static gint ett_collectd_unknown = - 1 ;
2009-09-15 01:34:01 +00:00
static gint st_collectd_packets = - 1 ;
static gint st_collectd_values = - 1 ;
static gint st_collectd_values_hosts = - 1 ;
static gint st_collectd_values_plugins = - 1 ;
static gint st_collectd_values_types = - 1 ;
2013-09-01 13:05:27 +00:00
static expert_field ei_collectd_type = EI_INIT ;
static expert_field ei_collectd_invalid_length = EI_INIT ;
static expert_field ei_collectd_data_valcnt = EI_INIT ;
static expert_field ei_collectd_garbage = EI_INIT ;
2009-09-14 01:36:26 +00:00
/* Prototype for the handoff function */
void proto_reg_handoff_collectd ( void ) ;
2013-05-17 00:06:26 +00:00
static nstime_t
collectd_time_to_nstime ( guint64 t )
{
nstime_t nstime = { 0 , 0 } ;
nstime . secs = ( time_t ) ( t / 1073741824 ) ;
nstime . nsecs = ( int ) ( ( ( double ) ( t % 1073741824 ) ) / 1.073741824 ) ;
return ( nstime ) ;
}
2009-09-15 01:34:01 +00:00
static void
collectd_stats_tree_init ( stats_tree * st )
{
st_collectd_packets = stats_tree_create_node ( st , " Packets " , 0 , FALSE ) ;
st_collectd_values = stats_tree_create_node ( st , " Values " , 0 , TRUE ) ;
st_collectd_values_hosts = stats_tree_create_pivot ( st , " By host " ,
st_collectd_values ) ;
st_collectd_values_plugins = stats_tree_create_pivot ( st , " By plugin " ,
st_collectd_values ) ;
st_collectd_values_types = stats_tree_create_pivot ( st , " By type " ,
st_collectd_values ) ;
} /* void collectd_stats_tree_init */
static int
collectd_stats_tree_packet ( stats_tree * st , packet_info * pinfo _U_ ,
epan_dissect_t * edt _U_ , const void * user_data )
{
const tap_data_t * td ;
string_counter_t * sc ;
2013-03-15 22:40:15 +00:00
td = ( const tap_data_t * ) user_data ;
2009-09-15 01:34:01 +00:00
if ( td = = NULL )
return ( - 1 ) ;
tick_stat_node ( st , " Packets " , 0 , FALSE ) ;
increase_stat_node ( st , " Values " , 0 , TRUE , td - > values_num ) ;
for ( sc = td - > hosts ; sc ! = NULL ; sc = sc - > next )
{
gint i ;
for ( i = 0 ; i < sc - > count ; i + + )
stats_tree_tick_pivot ( st , st_collectd_values_hosts ,
sc - > string ) ;
}
for ( sc = td - > plugins ; sc ! = NULL ; sc = sc - > next )
{
gint i ;
for ( i = 0 ; i < sc - > count ; i + + )
stats_tree_tick_pivot ( st , st_collectd_values_plugins ,
sc - > string ) ;
}
for ( sc = td - > types ; sc ! = NULL ; sc = sc - > next )
{
gint i ;
for ( i = 0 ; i < sc - > count ; i + + )
stats_tree_tick_pivot ( st , st_collectd_values_types ,
sc - > string ) ;
}
return ( 1 ) ;
} /* int collectd_stats_tree_packet */
static void
collectd_stats_tree_register ( void )
{
stats_tree_register ( " collectd " , " collectd " , " Collectd " , 0 ,
collectd_stats_tree_packet ,
collectd_stats_tree_init , NULL ) ;
} /* void register_collectd_stat_trees */
2013-05-17 00:06:26 +00:00
static void
collectd_proto_tree_add_assembled_metric ( tvbuff_t * tvb ,
gint offset , gint length ,
value_data_t const * vdispatch , proto_tree * root )
{
proto_item * root_item ;
proto_tree * subtree ;
nstime_t nstime ;
2014-06-24 00:39:28 +00:00
subtree = proto_tree_add_subtree ( root , tvb , offset + 6 , length - 6 ,
ett_collectd_dispatch , & root_item , " Assembled metric " ) ;
2013-05-17 00:06:26 +00:00
PROTO_ITEM_SET_GENERATED ( root_item ) ;
proto_tree_add_string ( subtree , hf_collectd_data_host , tvb ,
vdispatch - > host_off , vdispatch - > host_len ,
STR_NONNULL ( vdispatch - > host ) ) ;
proto_tree_add_string ( subtree , hf_collectd_data_plugin , tvb ,
vdispatch - > plugin_off , vdispatch - > plugin_len ,
STR_NONNULL ( vdispatch - > plugin ) ) ;
if ( vdispatch - > plugin_instance )
proto_tree_add_string ( subtree ,
hf_collectd_data_plugin_inst , tvb ,
vdispatch - > plugin_instance_off ,
vdispatch - > plugin_instance_len ,
vdispatch - > plugin_instance ) ;
proto_tree_add_string ( subtree , hf_collectd_data_type , tvb ,
vdispatch - > type_off , vdispatch - > type_len ,
STR_NONNULL ( vdispatch - > type ) ) ;
if ( vdispatch - > type_instance )
proto_tree_add_string ( subtree ,
hf_collectd_data_type_inst , tvb ,
vdispatch - > type_instance_off ,
vdispatch - > type_instance_len ,
vdispatch - > type_instance ) ;
nstime = collectd_time_to_nstime ( vdispatch - > time ) ;
proto_tree_add_time ( subtree , hf_collectd_data_time , tvb ,
vdispatch - > time_off , /* length = */ 8 , & nstime ) ;
nstime = collectd_time_to_nstime ( vdispatch - > interval ) ;
proto_tree_add_time ( subtree , hf_collectd_data_interval , tvb ,
vdispatch - > interval_off , /* length = */ 8 , & nstime ) ;
}
static void
collectd_proto_tree_add_assembled_notification ( tvbuff_t * tvb ,
gint offset , gint length ,
notify_data_t const * ndispatch , proto_tree * root )
{
proto_item * root_item ;
proto_tree * subtree ;
nstime_t nstime ;
2014-06-24 00:39:28 +00:00
subtree = proto_tree_add_subtree ( root , tvb , offset + 6 , length - 6 ,
ett_collectd_dispatch , & root_item , " Assembled notification " ) ;
2013-05-17 00:06:26 +00:00
PROTO_ITEM_SET_GENERATED ( root_item ) ;
proto_tree_add_string ( subtree , hf_collectd_data_host , tvb ,
ndispatch - > host_off , ndispatch - > host_len ,
STR_NONNULL ( ndispatch - > host ) ) ;
nstime = collectd_time_to_nstime ( ndispatch - > time ) ;
proto_tree_add_time ( subtree , hf_collectd_data_time , tvb ,
ndispatch - > time_off , /* length = */ 8 , & nstime ) ;
2013-07-23 05:19:44 +00:00
proto_tree_add_uint64 ( subtree , hf_collectd_data_severity , tvb ,
2013-05-17 00:06:26 +00:00
ndispatch - > severity_off , /* length = */ 8 ,
ndispatch - > severity ) ;
proto_tree_add_string ( subtree , hf_collectd_data_message , tvb ,
ndispatch - > message_off , ndispatch - > message_len ,
ndispatch - > message ) ;
}
2009-09-14 01:36:26 +00:00
static int
dissect_collectd_string ( tvbuff_t * tvb , packet_info * pinfo , gint type_hf ,
gint offset , gint * ret_offset , gint * ret_length ,
gchar * * ret_string , proto_tree * tree_root ,
proto_item * * ret_item )
{
proto_tree * pt ;
proto_item * pi ;
gint type ;
gint length ;
gint size ;
2009-09-15 00:18:40 +00:00
size = tvb_reported_length_remaining ( tvb , offset ) ;
2009-09-14 01:36:26 +00:00
if ( size < 4 )
{
/* This should never happen, because `dissect_collectd' checks
* for this condition already . */
return ( - 1 ) ;
}
type = tvb_get_ntohs ( tvb , offset ) ;
length = tvb_get_ntohs ( tvb , offset + 2 ) ;
2014-08-01 14:08:57 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , length ,
ett_collectd_string , & pi , " collectd %s segment: " ,
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-14 01:36:26 +00:00
if ( length > size )
{
2014-08-01 14:08:57 +00:00
proto_item_append_text ( pt , " Length = %i <BAD> " , length ) ;
expert_add_info_format ( pinfo , pt , & ei_collectd_invalid_length ,
2009-09-14 01:36:26 +00:00
" String part with invalid part length: "
" Part is longer than rest of package. " ) ;
return ( - 1 ) ;
}
* ret_offset = offset + 4 ;
* ret_length = length - 4 ;
2014-06-17 15:30:58 +00:00
* ret_string = tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , * ret_offset , * ret_length , ENC_ASCII ) ;
2014-08-01 14:08:57 +00:00
proto_item_append_text ( pt , " \" %s \" " , * ret_string ) ;
2009-09-14 01:36:26 +00:00
if ( ret_item ! = NULL )
* ret_item = pi ;
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 , length ) ;
2011-10-27 20:30:38 +00:00
proto_tree_add_item ( pt , type_hf , tvb , * ret_offset , * ret_length , ENC_ASCII | ENC_NA ) ;
2009-09-14 01:36:26 +00:00
return ( 0 ) ;
} /* int dissect_collectd_string */
static int
dissect_collectd_integer ( tvbuff_t * tvb , packet_info * pinfo , gint type_hf ,
gint offset , gint * ret_offset , guint64 * ret_value ,
proto_tree * tree_root , proto_item * * ret_item )
{
proto_tree * pt ;
proto_item * pi ;
gint type ;
gint length ;
gint size ;
2009-09-15 00:18:40 +00:00
size = tvb_reported_length_remaining ( tvb , offset ) ;
2009-09-14 01:36:26 +00:00
if ( size < 4 )
{
/* This should never happen, because `dissect_collectd' checks
* for this condition already . */
return ( - 1 ) ;
}
type = tvb_get_ntohs ( tvb , offset ) ;
length = tvb_get_ntohs ( tvb , offset + 2 ) ;
if ( size < 12 )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_integer , NULL , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-14 01:36:26 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 ,
type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 ,
length ) ;
2013-09-01 13:05:27 +00:00
proto_tree_add_expert_format ( pt , pinfo , & ei_collectd_garbage , tvb , offset + 4 , - 1 ,
2009-09-14 11:26:03 +00:00
" Garbage at end of packet: Length = %i <BAD> " ,
size - 4 ) ;
2009-09-14 01:36:26 +00:00
return ( - 1 ) ;
}
if ( length ! = 12 )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_integer , & pi , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-14 01:36:26 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 ,
type ) ;
pi = proto_tree_add_uint ( pt , hf_collectd_length , tvb ,
offset + 2 , 2 , length ) ;
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , pi , & ei_collectd_invalid_length ,
2009-09-14 01:36:26 +00:00
" Invalid length field for an integer part. " ) ;
return ( - 1 ) ;
}
* ret_offset = offset + 4 ;
* ret_value = tvb_get_ntoh64 ( tvb , offset + 4 ) ;
2013-05-17 00:06:26 +00:00
/* Convert the version 4.* time format to the version 5.* time format. */
if ( ( type = = TYPE_TIME ) | | ( type = = TYPE_INTERVAL ) )
* ret_value * = 1073741824 ;
/* Create an entry in the protocol tree for this part. The value is
* printed depending on the " type " variable : TIME { , _HR } as absolute
* time , INTERVAL { , _HR } as relative time , uint64 otherwise . */
if ( ( type = = TYPE_TIME ) | | ( type = = TYPE_TIME_HR ) )
{
nstime_t nstime ;
gchar * strtime ;
nstime = collectd_time_to_nstime ( * ret_value ) ;
2014-06-16 06:42:14 +00:00
strtime = abs_time_to_str ( wmem_packet_scope ( ) , & nstime , ABSOLUTE_TIME_LOCAL , /* show_zone = */ TRUE ) ;
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , length ,
ett_collectd_integer , & pi , " collectd %s segment: %s " ,
2013-05-17 00:06:26 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ,
STR_NONNULL ( strtime ) ) ;
}
else if ( ( type = = TYPE_INTERVAL ) | | ( type = = TYPE_INTERVAL_HR ) )
{
nstime_t nstime ;
gchar * strtime ;
nstime = collectd_time_to_nstime ( * ret_value ) ;
2014-06-16 06:42:14 +00:00
strtime = rel_time_to_str ( wmem_packet_scope ( ) , & nstime ) ;
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , length ,
ett_collectd_integer , & pi , " collectd %s segment: %s " ,
2013-05-17 00:06:26 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ,
strtime ) ;
}
else
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , length ,
ett_collectd_integer , & pi , " collectd %s segment: % " G_GINT64_MODIFIER " u " ,
2013-05-17 00:06:26 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ,
* ret_value ) ;
}
2009-09-14 01:36:26 +00:00
if ( ret_item ! = NULL )
* ret_item = pi ;
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 ,
length ) ;
2013-05-17 00:06:26 +00:00
if ( ( type = = TYPE_TIME ) | | ( type = = TYPE_INTERVAL )
| | ( type = = TYPE_TIME_HR ) | | ( type = = TYPE_INTERVAL_HR ) )
{
nstime_t nstime ;
nstime = collectd_time_to_nstime ( * ret_value ) ;
proto_tree_add_time ( pt , type_hf , tvb , offset + 4 , 8 , & nstime ) ;
}
else
{
proto_tree_add_item ( pt , type_hf , tvb , offset + 4 , 8 , ENC_BIG_ENDIAN ) ;
}
2009-09-14 01:36:26 +00:00
return ( 0 ) ;
} /* int dissect_collectd_integer */
static void
dissect_collectd_values ( tvbuff_t * tvb , gint msg_off , gint val_cnt ,
proto_tree * collectd_tree )
{
proto_tree * values_tree , * value_tree ;
gint i ;
2014-06-24 00:39:28 +00:00
values_tree = proto_tree_add_subtree_format ( collectd_tree , tvb , msg_off + 6 , val_cnt * 9 ,
ett_collectd_value , NULL , " %d value%s " , val_cnt ,
2009-09-14 01:36:26 +00:00
plurality ( val_cnt , " " , " s " ) ) ;
2009-09-15 00:18:40 +00:00
for ( i = 0 ; i < val_cnt ; i + + )
{
2009-09-14 01:36:26 +00:00
gint value_offset ;
gint value_type_offset ;
guint8 value_type ;
/* Calculate the offsets of the type byte and the actual value. */
value_offset = msg_off + 6
+ val_cnt /* value types */
+ ( i * 8 ) ; /* previous values */
value_type_offset = msg_off + 6 + i ;
value_type = tvb_get_guint8 ( tvb , value_type_offset ) ;
switch ( value_type ) {
case TYPE_VALUE_COUNTER :
{
guint64 val64 ;
val64 = tvb_get_ntoh64 ( tvb , value_offset ) ;
2014-06-24 00:39:28 +00:00
value_tree = proto_tree_add_subtree_format ( values_tree , tvb , msg_off + 6 ,
val_cnt * 9 , ett_collectd_valinfo , NULL ,
2009-09-14 01:36:26 +00:00
" Counter: % " G_GINT64_MODIFIER " u " , val64 ) ;
proto_tree_add_item ( value_tree , hf_collectd_val_type ,
2011-10-06 03:35:44 +00:00
tvb , value_type_offset , 1 , ENC_BIG_ENDIAN ) ;
2009-09-14 01:36:26 +00:00
proto_tree_add_item ( value_tree ,
hf_collectd_val_counter , tvb ,
2011-10-06 03:35:44 +00:00
value_offset , 8 , ENC_BIG_ENDIAN ) ;
2009-09-14 01:36:26 +00:00
break ;
}
case TYPE_VALUE_GAUGE :
{
gdouble val ;
val = tvb_get_letohieee_double ( tvb , value_offset ) ;
2014-06-24 00:39:28 +00:00
value_tree = proto_tree_add_subtree_format ( values_tree , tvb , msg_off + 6 ,
val_cnt * 9 , ett_collectd_valinfo , NULL ,
2009-09-14 11:26:03 +00:00
" Gauge: %g " , val ) ;
2009-09-14 01:36:26 +00:00
proto_tree_add_item ( value_tree , hf_collectd_val_type ,
2011-10-06 03:35:44 +00:00
tvb , value_type_offset , 1 , ENC_BIG_ENDIAN ) ;
2009-09-14 01:36:26 +00:00
/* Set the `little endian' flag to TRUE here, because
* collectd stores doubles in x86 representation . */
proto_tree_add_item ( value_tree , hf_collectd_val_gauge ,
2011-10-06 03:35:44 +00:00
tvb , value_offset , 8 , ENC_LITTLE_ENDIAN ) ;
2009-09-14 01:36:26 +00:00
break ;
}
2009-09-16 19:02:51 +00:00
case TYPE_VALUE_DERIVE :
{
gint64 val64 ;
val64 = tvb_get_ntoh64 ( tvb , value_offset ) ;
2014-06-24 00:39:28 +00:00
value_tree = proto_tree_add_subtree_format ( values_tree , tvb , msg_off + 6 ,
val_cnt * 9 , ett_collectd_valinfo , NULL ,
2009-09-16 19:02:51 +00:00
" Derive: % " G_GINT64_MODIFIER " i " , val64 ) ;
proto_tree_add_item ( value_tree , hf_collectd_val_type ,
2011-10-06 03:35:44 +00:00
tvb , value_type_offset , 1 , ENC_BIG_ENDIAN ) ;
2009-09-16 19:02:51 +00:00
proto_tree_add_item ( value_tree ,
hf_collectd_val_derive , tvb ,
2011-10-06 03:35:44 +00:00
value_offset , 8 , ENC_BIG_ENDIAN ) ;
2009-09-16 19:02:51 +00:00
break ;
}
case TYPE_VALUE_ABSOLUTE :
{
guint64 val64 ;
val64 = tvb_get_ntoh64 ( tvb , value_offset ) ;
2014-06-24 00:39:28 +00:00
value_tree = proto_tree_add_subtree_format ( values_tree , tvb , msg_off + 6 ,
val_cnt * 9 , ett_collectd_valinfo , NULL ,
2009-09-16 19:02:51 +00:00
" Absolute: % " G_GINT64_MODIFIER " u " , val64 ) ;
proto_tree_add_item ( value_tree , hf_collectd_val_type ,
2011-10-06 03:35:44 +00:00
tvb , value_type_offset , 1 , ENC_BIG_ENDIAN ) ;
2009-09-16 19:02:51 +00:00
proto_tree_add_item ( value_tree ,
hf_collectd_val_absolute , tvb ,
2011-10-06 03:35:44 +00:00
value_offset , 8 , ENC_BIG_ENDIAN ) ;
2009-09-16 19:02:51 +00:00
break ;
}
2009-09-14 01:36:26 +00:00
default :
{
guint64 val64 ;
val64 = tvb_get_ntoh64 ( tvb , value_offset ) ;
2014-06-24 00:39:28 +00:00
value_tree = proto_tree_add_subtree_format ( values_tree , tvb , msg_off + 6 ,
val_cnt * 9 , ett_collectd_valinfo , NULL ,
2009-09-14 01:36:26 +00:00
" Unknown: % " G_GINT64_MODIFIER " x " ,
val64 ) ;
proto_tree_add_item ( value_tree , hf_collectd_val_type ,
2011-10-06 03:35:44 +00:00
tvb , value_type_offset , 1 , ENC_BIG_ENDIAN ) ;
2009-09-14 01:36:26 +00:00
proto_tree_add_item ( value_tree , hf_collectd_val_unknown ,
2011-10-06 03:35:44 +00:00
tvb , value_offset , 8 , ENC_BIG_ENDIAN ) ;
2009-09-14 01:36:26 +00:00
break ;
}
} /* switch (value_type) */
} /* for (i = 0; i < val_cnt; i++) */
} /* void dissect_collectd_values */
static int
dissect_collectd_part_values ( tvbuff_t * tvb , packet_info * pinfo , gint offset ,
value_data_t * vdispatch , proto_tree * tree_root )
{
proto_tree * pt ;
proto_item * pi ;
gint type ;
gint length ;
gint size ;
gint values_count ;
gint corrected_values_count ;
2009-09-15 00:18:40 +00:00
size = tvb_reported_length_remaining ( tvb , offset ) ;
2009-09-14 01:36:26 +00:00
if ( size < 4 )
{
/* This should never happen, because `dissect_collectd' checks
* for this condition already . */
return ( - 1 ) ;
}
type = tvb_get_ntohs ( tvb , offset ) ;
length = tvb_get_ntohs ( tvb , offset + 2 ) ;
if ( size < 15 )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_part_value , NULL , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-14 01:36:26 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 ,
length ) ;
2013-09-01 13:05:27 +00:00
proto_tree_add_expert_format ( pt , pinfo , & ei_collectd_garbage , tvb , offset + 4 , - 1 ,
2009-09-14 11:26:03 +00:00
" Garbage at end of packet: Length = %i <BAD> " ,
size - 4 ) ;
2009-09-14 01:36:26 +00:00
return ( - 1 ) ;
}
if ( ( length < 15 ) | | ( ( length % 9 ) ! = 6 ) )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_part_value , & pi , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-14 01:36:26 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
pi = proto_tree_add_uint ( pt , hf_collectd_length , tvb ,
offset + 2 , 2 , length ) ;
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , pi , & ei_collectd_invalid_length ,
2009-09-14 01:36:26 +00:00
" Invalid length field for a values part. " ) ;
return ( - 1 ) ;
}
values_count = tvb_get_ntohs ( tvb , offset + 4 ) ;
corrected_values_count = ( length - 6 ) / 9 ;
if ( values_count ! = corrected_values_count )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , length ,
2014-10-02 21:47:19 +00:00
ett_collectd_part_value , NULL ,
2009-09-14 11:26:03 +00:00
" collectd %s segment: %d (%d) value%s <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ,
2009-09-14 11:26:03 +00:00
values_count , corrected_values_count ,
2009-09-14 13:11:26 +00:00
plurality ( values_count , " " , " s " ) ) ;
2009-09-14 01:36:26 +00:00
}
else
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , length ,
2014-10-02 21:47:19 +00:00
ett_collectd_part_value , NULL ,
2009-09-14 11:26:03 +00:00
" collectd %s segment: %d value%s " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ,
2009-09-14 11:26:03 +00:00
values_count ,
2009-09-14 13:11:26 +00:00
plurality ( values_count , " " , " s " ) ) ;
2009-09-14 01:36:26 +00:00
}
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 , length ) ;
pi = proto_tree_add_item ( pt , hf_collectd_data_valcnt , tvb ,
2011-10-06 03:35:44 +00:00
offset + 4 , 2 , ENC_BIG_ENDIAN ) ;
2009-09-14 01:36:26 +00:00
if ( values_count ! = corrected_values_count )
2013-09-01 13:05:27 +00:00
expert_add_info ( pinfo , pi , & ei_collectd_data_valcnt ) ;
2009-09-14 01:36:26 +00:00
values_count = corrected_values_count ;
dissect_collectd_values ( tvb , offset , values_count , pt ) ;
2013-05-17 00:06:26 +00:00
collectd_proto_tree_add_assembled_metric ( tvb , offset + 6 , length - 6 ,
vdispatch , pt ) ;
2009-09-14 01:36:26 +00:00
return ( 0 ) ;
2009-09-15 00:18:40 +00:00
} /* void dissect_collectd_part_values */
static int
dissect_collectd_signature ( tvbuff_t * tvb , packet_info * pinfo ,
gint offset , proto_tree * tree_root )
{
proto_item * pi ;
proto_tree * pt ;
gint type ;
gint length ;
gint size ;
size = tvb_reported_length_remaining ( tvb , offset ) ;
if ( size < 4 )
{
/* This should never happen, because `dissect_collectd' checks
* for this condition already . */
return ( - 1 ) ;
}
type = tvb_get_ntohs ( tvb , offset ) ;
length = tvb_get_ntohs ( tvb , offset + 2 ) ;
if ( size < 36 ) /* remaining packet size too small for signature */
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_signature , NULL , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 ,
length ) ;
2013-09-01 13:05:27 +00:00
proto_tree_add_expert_format ( pt , pinfo , & ei_collectd_garbage , tvb , offset + 4 , - 1 ,
2009-09-15 00:18:40 +00:00
" Garbage at end of packet: Length = %i <BAD> " ,
size - 4 ) ;
return ( - 1 ) ;
}
if ( length < 36 )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_signature , NULL , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
pi = proto_tree_add_uint ( pt , hf_collectd_length , tvb ,
offset + 2 , 2 , length ) ;
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , pi , & ei_collectd_invalid_length ,
2009-09-15 00:18:40 +00:00
" Invalid length field for a signature part. " ) ;
return ( - 1 ) ;
}
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , length ,
ett_collectd_signature , NULL , " collectd %s segment: HMAC-SHA-256 " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 ,
length ) ;
2011-10-04 22:44:31 +00:00
proto_tree_add_item ( pt , hf_collectd_data_sighash , tvb , offset + 4 , 32 , ENC_NA ) ;
2011-10-15 18:46:26 +00:00
proto_tree_add_item ( pt , hf_collectd_data_username , tvb , offset + 36 , length - 36 , ENC_ASCII | ENC_NA ) ;
2009-09-15 00:18:40 +00:00
return ( 0 ) ;
} /* int dissect_collectd_signature */
static int
dissect_collectd_encrypted ( tvbuff_t * tvb , packet_info * pinfo ,
gint offset , proto_tree * tree_root )
{
proto_item * pi ;
proto_tree * pt ;
gint type ;
gint length ;
gint size ;
gint username_length ;
size = tvb_reported_length_remaining ( tvb , offset ) ;
if ( size < 4 )
{
/* This should never happen, because `dissect_collectd' checks
* for this condition already . */
return ( - 1 ) ;
}
type = tvb_get_ntohs ( tvb , offset ) ;
length = tvb_get_ntohs ( tvb , offset + 2 ) ;
if ( size < 42 ) /* remaining packet size too small for signature */
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_encryption , NULL , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 ,
length ) ;
2013-09-01 13:05:27 +00:00
proto_tree_add_expert_format ( pt , pinfo , & ei_collectd_garbage , tvb , offset + 4 , - 1 ,
2009-09-15 00:18:40 +00:00
" Garbage at end of packet: Length = %i <BAD> " ,
size - 4 ) ;
return ( - 1 ) ;
}
if ( length < 42 )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_encryption , NULL , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
pi = proto_tree_add_uint ( pt , hf_collectd_length , tvb ,
offset + 2 , 2 , length ) ;
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , pi , & ei_collectd_invalid_length ,
2009-09-15 00:18:40 +00:00
" Invalid length field for an encryption part. " ) ;
return ( - 1 ) ;
}
username_length = tvb_get_ntohs ( tvb , offset + 4 ) ;
if ( username_length > ( length - 42 ) )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , - 1 ,
ett_collectd_encryption , NULL , " collectd %s segment: <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb ,
offset + 2 , 2 , length ) ;
pi = proto_tree_add_uint ( pt , hf_collectd_data_username_len , tvb ,
offset + 4 , 2 , length ) ;
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , pi , & ei_collectd_invalid_length ,
2009-09-15 00:18:40 +00:00
" Invalid username length field for an encryption part. " ) ;
return ( - 1 ) ;
}
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( tree_root , tvb , offset , length ,
ett_collectd_encryption , NULL , " collectd %s segment: AES-256 " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( type , part_names , " UNKNOWN " ) ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset , 2 , type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb , offset + 2 , 2 , length ) ;
proto_tree_add_uint ( pt , hf_collectd_data_username_len , tvb , offset + 4 , 2 , username_length ) ;
2011-10-15 18:46:26 +00:00
proto_tree_add_item ( pt , hf_collectd_data_username , tvb , offset + 6 , username_length , ENC_ASCII | ENC_NA ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_item ( pt , hf_collectd_data_initvec , tvb ,
2011-10-04 22:44:31 +00:00
offset + ( 6 + username_length ) , 16 , ENC_NA ) ;
2009-09-15 00:18:40 +00:00
proto_tree_add_item ( pt , hf_collectd_data_encrypted , tvb ,
offset + ( 22 + username_length ) ,
2011-10-04 22:44:31 +00:00
length - ( 22 + username_length ) , ENC_NA ) ;
2009-09-15 00:18:40 +00:00
return ( 0 ) ;
} /* int dissect_collectd_encrypted */
2009-09-14 01:36:26 +00:00
2009-09-15 01:34:01 +00:00
static int
stats_account_string ( string_counter_t * * ret_list , const gchar * new_value )
{
string_counter_t * entry ;
if ( ret_list = = NULL )
return ( - 1 ) ;
if ( new_value = = NULL )
new_value = " (null) " ;
for ( entry = * ret_list ; entry ! = NULL ; entry = entry - > next )
if ( strcmp ( new_value , entry - > string ) = = 0 )
{
entry - > count + + ;
return ( 0 ) ;
}
2013-09-13 17:25:54 +00:00
entry = ( string_counter_t * ) wmem_alloc0 ( wmem_packet_scope ( ) , sizeof ( * entry ) ) ;
entry - > string = wmem_strdup ( wmem_packet_scope ( ) , new_value ) ;
2009-09-15 01:34:01 +00:00
entry - > count = 1 ;
entry - > next = * ret_list ;
* ret_list = entry ;
return ( 0 ) ;
}
2009-09-14 01:36:26 +00:00
static void
dissect_collectd ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree )
{
2009-09-15 01:34:01 +00:00
static tap_data_t tap_data ;
2009-09-14 01:36:26 +00:00
gint offset ;
gint size ;
gchar * pkt_host = NULL ;
gint pkt_plugins = 0 , pkt_values = 0 , pkt_messages = 0 , pkt_unknown = 0 , pkt_errors = 0 ;
value_data_t vdispatch ;
notify_data_t ndispatch ;
int status ;
proto_item * pi ;
proto_tree * collectd_tree ;
proto_tree * pt ;
memset ( & vdispatch , ' \0 ' , sizeof ( vdispatch ) ) ;
memset ( & ndispatch , ' \0 ' , sizeof ( ndispatch ) ) ;
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " collectd " ) ;
col_clear ( pinfo - > cinfo , COL_INFO ) ;
offset = 0 ;
size = tvb_reported_length ( tvb ) ;
/* create the collectd protocol tree */
2011-10-21 02:10:19 +00:00
pi = proto_tree_add_item ( tree , proto_collectd , tvb , 0 , - 1 , ENC_NA ) ;
2009-09-14 01:36:26 +00:00
collectd_tree = proto_item_add_subtree ( pi , ett_collectd ) ;
2009-09-15 01:34:01 +00:00
memset ( & tap_data , 0 , sizeof ( tap_data ) ) ;
2009-09-14 01:36:26 +00:00
status = 0 ;
2009-09-15 00:18:40 +00:00
while ( ( size > 0 ) & & ( status = = 0 ) )
{
2009-09-14 01:36:26 +00:00
gint part_type ;
gint part_length ;
/* Let's handle the easy case first real quick: All we do here
* is extract a host name and count the number of values ,
* plugins and notifications . The payload is not checked at
* all , but the same checks are run on the part_length stuff -
* it ' s important to keep an eye on that . */
2009-09-15 00:18:40 +00:00
if ( ! tree )
{
2009-09-14 01:36:26 +00:00
/* Check for garbage at end of packet. */
if ( size < 4 )
{
pkt_errors + + ;
break ;
}
part_type = tvb_get_ntohs ( tvb , offset ) ;
part_length = tvb_get_ntohs ( tvb , offset + 2 ) ;
/* Check if part_length is in the valid range. */
2009-09-15 00:18:40 +00:00
if ( ( part_length < 4 ) | | ( part_length > size ) )
{
2009-09-14 01:36:26 +00:00
pkt_errors + + ;
break ;
}
switch ( part_type ) {
case TYPE_HOST :
2014-06-17 15:30:58 +00:00
vdispatch . host = tvb_get_string_enc ( wmem_packet_scope ( ) , tvb ,
offset + 4 , part_length - 4 , ENC_ASCII ) ;
2009-09-14 01:36:26 +00:00
if ( pkt_host = = NULL )
2009-09-15 01:34:01 +00:00
pkt_host = vdispatch . host ;
2009-09-14 01:36:26 +00:00
break ;
case TYPE_TIME :
2013-05-17 00:06:26 +00:00
case TYPE_TIME_HR :
2009-09-14 01:36:26 +00:00
break ;
case TYPE_PLUGIN :
2014-06-17 15:30:58 +00:00
vdispatch . plugin = tvb_get_string_enc ( wmem_packet_scope ( ) , tvb ,
offset + 4 , part_length - 4 , ENC_ASCII ) ;
2009-09-14 01:36:26 +00:00
pkt_plugins + + ;
break ;
case TYPE_PLUGIN_INSTANCE :
break ;
case TYPE_TYPE :
2014-06-17 15:30:58 +00:00
vdispatch . type = tvb_get_string_enc ( wmem_packet_scope ( ) , tvb ,
offset + 4 , part_length - 4 , ENC_ASCII ) ;
2009-09-14 01:36:26 +00:00
break ;
case TYPE_TYPE_INSTANCE :
break ;
case TYPE_INTERVAL :
2013-05-17 00:06:26 +00:00
case TYPE_INTERVAL_HR :
2009-09-14 01:36:26 +00:00
break ;
case TYPE_VALUES :
2009-09-15 01:34:01 +00:00
{
2009-09-14 01:36:26 +00:00
pkt_values + + ;
2009-09-15 01:34:01 +00:00
tap_data . values_num + + ;
stats_account_string ( & tap_data . hosts ,
vdispatch . host ) ;
stats_account_string ( & tap_data . plugins ,
vdispatch . plugin ) ;
stats_account_string ( & tap_data . types ,
vdispatch . type ) ;
2009-09-14 01:36:26 +00:00
break ;
2009-09-15 01:34:01 +00:00
}
2009-09-14 01:36:26 +00:00
case TYPE_MESSAGE :
pkt_messages + + ;
break ;
case TYPE_SEVERITY :
break ;
default :
pkt_unknown + + ;
}
offset + = part_length ;
size - = part_length ;
continue ;
} /* if (!tree) */
/* Now we do the same steps again, but much more thoroughly. */
/* Check if there are at least four bytes left first.
* Four bytes are used to read the type and the length
* of the next part . If there ' s less , there ' s some garbage
* at the end of the packet . */
2009-09-15 00:18:40 +00:00
if ( size < 4 )
{
2013-09-01 13:43:26 +00:00
proto_tree_add_expert_format ( pi , pinfo , & ei_collectd_garbage , tvb ,
2009-09-14 11:26:03 +00:00
offset , - 1 ,
" Garbage at end of packet: Length = %i <BAD> " ,
size ) ;
2009-09-14 01:36:26 +00:00
pkt_errors + + ;
break ;
}
/* dissect a message entry */
part_type = tvb_get_ntohs ( tvb , offset ) ;
part_length = tvb_get_ntohs ( tvb , offset + 2 ) ;
/* Check if the length of the part is in the valid range. Don't
* confuse this with the above : Here we check the information
* provided in the packet . . */
2009-09-15 00:18:40 +00:00
if ( ( part_length < 4 ) | | ( part_length > size ) )
{
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( collectd_tree , tvb ,
offset , part_length , ett_collectd_invalid_length , NULL ,
2009-09-14 11:26:03 +00:00
" collectd %s segment: Length = %i <BAD> " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( part_type , part_names , " UNKNOWN " ) ,
2009-09-14 11:26:03 +00:00
part_length ) ;
2009-09-14 01:36:26 +00:00
proto_tree_add_uint ( pt , hf_collectd_type , tvb , offset ,
2 , part_type ) ;
pi = proto_tree_add_uint ( pt , hf_collectd_length , tvb ,
offset + 2 , 2 , part_length ) ;
if ( part_length < 4 )
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , pi , & ei_collectd_invalid_length ,
2009-09-14 01:36:26 +00:00
" Bad part length: Is %i, expected at least 4 " ,
part_length ) ;
else
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , pi , & ei_collectd_invalid_length ,
2009-09-14 01:36:26 +00:00
" Bad part length: Larger than remaining packet size. " ) ;
pkt_errors + + ;
break ;
}
/* The header information looks okay, let's tend to the actual
* payload in this part . */
switch ( part_type ) {
2009-09-15 00:18:40 +00:00
case TYPE_HOST :
{
2009-09-14 01:36:26 +00:00
status = dissect_collectd_string ( tvb , pinfo ,
hf_collectd_data_host ,
offset ,
& vdispatch . host_off ,
& vdispatch . host_len ,
& vdispatch . host ,
collectd_tree , /* item = */ NULL ) ;
if ( status ! = 0 )
pkt_errors + + ;
2009-09-15 00:18:40 +00:00
else
{
2009-09-14 01:36:26 +00:00
if ( pkt_host = = NULL )
pkt_host = vdispatch . host ;
ndispatch . host_off = vdispatch . host_off ;
ndispatch . host_len = vdispatch . host_len ;
ndispatch . host = vdispatch . host ;
}
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_PLUGIN :
{
2009-09-14 01:36:26 +00:00
status = dissect_collectd_string ( tvb , pinfo ,
hf_collectd_data_plugin ,
offset ,
& vdispatch . plugin_off ,
& vdispatch . plugin_len ,
& vdispatch . plugin ,
collectd_tree , /* item = */ NULL ) ;
if ( status ! = 0 )
pkt_errors + + ;
else
pkt_plugins + + ;
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_PLUGIN_INSTANCE :
{
2009-09-14 01:36:26 +00:00
status = dissect_collectd_string ( tvb , pinfo ,
hf_collectd_data_plugin_inst ,
offset ,
& vdispatch . plugin_instance_off ,
& vdispatch . plugin_instance_len ,
& vdispatch . plugin_instance ,
collectd_tree , /* item = */ NULL ) ;
if ( status ! = 0 )
pkt_errors + + ;
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_TYPE :
{
2009-09-14 01:36:26 +00:00
status = dissect_collectd_string ( tvb , pinfo ,
hf_collectd_data_type ,
offset ,
& vdispatch . type_off ,
& vdispatch . type_len ,
& vdispatch . type ,
collectd_tree , /* item = */ NULL ) ;
if ( status ! = 0 )
pkt_errors + + ;
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_TYPE_INSTANCE :
{
2009-09-14 01:36:26 +00:00
status = dissect_collectd_string ( tvb , pinfo ,
hf_collectd_data_type_inst ,
offset ,
& vdispatch . type_instance_off ,
& vdispatch . type_instance_len ,
& vdispatch . type_instance ,
collectd_tree , /* item = */ NULL ) ;
if ( status ! = 0 )
pkt_errors + + ;
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_TIME :
2013-05-17 00:06:26 +00:00
case TYPE_TIME_HR :
2009-09-15 00:18:40 +00:00
{
2009-09-14 01:36:26 +00:00
pi = NULL ;
status = dissect_collectd_integer ( tvb , pinfo ,
hf_collectd_data_time ,
offset ,
& vdispatch . time_off ,
& vdispatch . time ,
collectd_tree , & pi ) ;
if ( status ! = 0 )
pkt_errors + + ;
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_INTERVAL :
2013-05-17 00:06:26 +00:00
case TYPE_INTERVAL_HR :
2009-09-15 00:18:40 +00:00
{
2009-09-14 01:36:26 +00:00
status = dissect_collectd_integer ( tvb , pinfo ,
hf_collectd_data_interval ,
offset ,
& vdispatch . interval_off ,
& vdispatch . interval ,
collectd_tree , /* item = */ NULL ) ;
if ( status ! = 0 )
pkt_errors + + ;
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_VALUES :
{
2009-09-14 01:36:26 +00:00
status = dissect_collectd_part_values ( tvb , pinfo ,
offset ,
& vdispatch ,
collectd_tree ) ;
if ( status ! = 0 )
pkt_errors + + ;
else
pkt_values + + ;
2009-09-15 01:34:01 +00:00
tap_data . values_num + + ;
stats_account_string ( & tap_data . hosts ,
vdispatch . host ) ;
stats_account_string ( & tap_data . plugins ,
vdispatch . plugin ) ;
stats_account_string ( & tap_data . types ,
vdispatch . type ) ;
2009-09-14 01:36:26 +00:00
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_MESSAGE :
{
2009-09-14 01:36:26 +00:00
pi = NULL ;
status = dissect_collectd_string ( tvb , pinfo ,
hf_collectd_data_message ,
offset ,
& ndispatch . message_off ,
& ndispatch . message_len ,
& ndispatch . message ,
collectd_tree , & pi ) ;
if ( status ! = 0 )
{
pkt_errors + + ;
break ;
}
pkt_messages + + ;
pt = proto_item_get_subtree ( pi ) ;
2013-05-17 00:06:26 +00:00
collectd_proto_tree_add_assembled_notification ( tvb ,
offset + 4 , part_length - 1 ,
& ndispatch , pt ) ;
2009-09-14 01:36:26 +00:00
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_SEVERITY :
{
2009-09-14 01:36:26 +00:00
pi = NULL ;
status = dissect_collectd_integer ( tvb , pinfo ,
hf_collectd_data_severity ,
offset ,
& ndispatch . severity_off ,
& ndispatch . severity ,
collectd_tree , & pi ) ;
if ( status ! = 0 )
pkt_errors + + ;
2009-09-15 00:18:40 +00:00
else
{
2009-09-14 01:36:26 +00:00
proto_item_set_text ( pi ,
" collectd SEVERITY segment: "
" %s (% " G_GINT64_MODIFIER " u) " ,
2013-07-26 21:51:39 +00:00
val64_to_str_const ( ndispatch . severity , severity_names , " UNKNOWN " ) ,
2009-09-14 01:36:26 +00:00
ndispatch . severity ) ;
}
break ;
}
2009-09-15 00:18:40 +00:00
case TYPE_SIGN_SHA256 :
{
status = dissect_collectd_signature ( tvb , pinfo ,
offset ,
collectd_tree ) ;
if ( status ! = 0 )
pkt_errors + + ;
break ;
}
case TYPE_ENCR_AES256 :
{
status = dissect_collectd_encrypted ( tvb , pinfo ,
offset , collectd_tree ) ;
if ( status ! = 0 )
pkt_errors + + ;
break ;
}
default :
{
2009-09-14 01:36:26 +00:00
pkt_unknown + + ;
2014-06-24 00:39:28 +00:00
pt = proto_tree_add_subtree_format ( collectd_tree , tvb ,
offset , part_length , ett_collectd_unknown , NULL ,
2009-09-14 11:26:03 +00:00
" collectd %s segment: %i bytes " ,
2012-08-10 22:55:02 +00:00
val_to_str_const ( part_type , part_names , " UNKNOWN " ) ,
2009-09-14 11:26:03 +00:00
part_length ) ;
2009-09-14 01:36:26 +00:00
pi = proto_tree_add_uint ( pt , hf_collectd_type , tvb ,
offset , 2 , part_type ) ;
proto_tree_add_uint ( pt , hf_collectd_length , tvb ,
offset + 2 , 2 , part_length ) ;
proto_tree_add_item ( pt , hf_collectd_data , tvb ,
2011-10-04 22:44:31 +00:00
offset + 4 , part_length - 4 , ENC_NA ) ;
2009-09-14 01:36:26 +00:00
2013-09-09 00:44:09 +00:00
expert_add_info_format ( pinfo , pi , & ei_collectd_type ,
2009-09-14 01:36:26 +00:00
" Unknown part type %#x. Cannot decode data. " ,
part_type ) ;
}
} /* switch (part_type) */
offset + = part_length ;
size - = part_length ;
} /* while ((size > 4) && (status == 0)) */
if ( pkt_errors & & pkt_unknown )
col_add_fstr ( pinfo - > cinfo , COL_INFO ,
" Host=%s, %2d value%s for %d plugin%s %d message%s %d unknown, %d error%s " ,
pkt_host ,
pkt_values , plurality ( pkt_values , " " , " s " ) ,
pkt_plugins , plurality ( pkt_plugins , " , " , " s, " ) ,
pkt_messages , plurality ( pkt_messages , " , " , " s, " ) ,
pkt_unknown ,
pkt_errors , plurality ( pkt_errors , " " , " s " ) ) ;
else if ( pkt_errors )
col_add_fstr ( pinfo - > cinfo , COL_INFO , " Host=%s, %2d value%s for %d plugin%s %d message%s %d error%s " ,
pkt_host ,
pkt_values , plurality ( pkt_values , " " , " s " ) ,
pkt_plugins , plurality ( pkt_plugins , " , " , " s, " ) ,
pkt_messages , plurality ( pkt_messages , " , " , " s, " ) ,
pkt_errors , plurality ( pkt_errors , " " , " s " ) ) ;
else if ( pkt_unknown )
col_add_fstr ( pinfo - > cinfo , COL_INFO ,
" Host=%s, %2d value%s for %d plugin%s %d message%s %d unknown " ,
pkt_host ,
pkt_values , plurality ( pkt_values , " " , " s " ) ,
pkt_plugins , plurality ( pkt_plugins , " , " , " s, " ) ,
pkt_messages , plurality ( pkt_messages , " , " , " s, " ) ,
pkt_unknown ) ;
else
col_add_fstr ( pinfo - > cinfo , COL_INFO , " Host=%s, %2d value%s for %d plugin%s %d message%s " ,
pkt_host ,
pkt_values , plurality ( pkt_values , " " , " s " ) ,
pkt_plugins , plurality ( pkt_plugins , " , " , " s, " ) ,
pkt_messages , plurality ( pkt_messages , " " , " s " ) ) ;
2009-09-15 01:34:01 +00:00
/* Dispatch tap data. */
tap_queue_packet ( tap_collectd , pinfo , & tap_data ) ;
2009-09-14 01:36:26 +00:00
} /* void dissect_collectd */
void proto_register_collectd ( void )
{
module_t * collectd_module ;
2013-09-01 13:05:27 +00:00
expert_module_t * expert_collectd ;
2009-09-14 01:36:26 +00:00
/* Setup list of header fields */
static hf_register_info hf [ ] = {
{ & hf_collectd_type ,
{ " Type " , " collectd.type " , FT_UINT16 , BASE_HEX ,
VALS ( part_names ) , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_length ,
{ " Length " , " collectd.len " , FT_UINT16 , BASE_DEC ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data ,
2009-10-07 23:08:22 +00:00
{ " Payload " , " collectd.data " , FT_BYTES , BASE_NONE ,
2009-09-14 01:36:26 +00:00
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_host ,
{ " Host name " , " collectd.data.host " , FT_STRING , BASE_NONE ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_interval ,
2013-05-17 00:06:26 +00:00
{ " Interval " , " collectd.data.interval " , FT_RELATIVE_TIME , BASE_NONE ,
2009-09-14 01:36:26 +00:00
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_time ,
2013-05-17 00:06:26 +00:00
{ " Timestamp " , " collectd.data.time " , FT_ABSOLUTE_TIME , ABSOLUTE_TIME_LOCAL ,
2009-09-14 01:36:26 +00:00
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_plugin ,
{ " Plugin " , " collectd.data.plugin " , FT_STRING , BASE_NONE ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_plugin_inst ,
{ " Plugin instance " , " collectd.data.plugin.inst " , FT_STRING , BASE_NONE ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_type ,
{ " Type " , " collectd.data.type " , FT_STRING , BASE_NONE ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_type_inst ,
{ " Type instance " , " collectd.data.type.inst " , FT_STRING , BASE_NONE ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_valcnt ,
{ " Value count " , " collectd.data.valcnt " , FT_UINT16 , BASE_DEC ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_val_type ,
{ " Value type " , " collectd.val.type " , FT_UINT8 , BASE_HEX ,
VALS ( valuetypenames ) , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_val_counter ,
{ " Counter value " , " collectd.val.counter " , FT_UINT64 , BASE_DEC ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_val_gauge ,
{ " Gauge value " , " collectd.val.gauge " , FT_DOUBLE , BASE_NONE ,
NULL , 0x0 , NULL , HFILL }
} ,
2009-09-16 19:02:51 +00:00
{ & hf_collectd_val_derive ,
{ " Derive value " , " collectd.val.derive " , FT_INT64 , BASE_DEC ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_val_absolute ,
{ " Absolute value " , " collectd.val.absolute " , FT_UINT64 , BASE_DEC ,
NULL , 0x0 , NULL , HFILL }
} ,
2009-09-14 01:36:26 +00:00
{ & hf_collectd_val_unknown ,
{ " Value of unknown type " , " collectd.val.unknown " , FT_UINT64 , BASE_HEX ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_severity ,
2013-07-26 21:51:39 +00:00
{ " Severity " , " collectd.data.severity " , FT_UINT64 , BASE_HEX | BASE_VAL64_STRING ,
2014-01-30 17:43:52 +00:00
VALS64 ( severity_names ) ,
2013-05-17 00:06:26 +00:00
0x0 , NULL , HFILL }
2009-09-14 01:36:26 +00:00
} ,
{ & hf_collectd_data_message ,
{ " Message " , " collectd.data.message " , FT_STRING , BASE_NONE ,
NULL , 0x0 , NULL , HFILL }
} ,
2009-09-15 00:18:40 +00:00
{ & hf_collectd_data_sighash ,
2009-10-07 23:08:22 +00:00
{ " Signature " , " collectd.data.sighash " , FT_BYTES , BASE_NONE ,
2009-09-15 00:18:40 +00:00
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_initvec ,
2009-10-07 23:08:22 +00:00
{ " Init vector " , " collectd.data.initvec " , FT_BYTES , BASE_NONE ,
2009-09-15 00:18:40 +00:00
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_username_len ,
{ " Username length " , " collectd.data.username_length " , FT_UINT16 , BASE_DEC ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_username ,
{ " Username " , " collectd.data.username " , FT_STRING , BASE_NONE ,
NULL , 0x0 , NULL , HFILL }
} ,
{ & hf_collectd_data_encrypted ,
2009-10-07 23:08:22 +00:00
{ " Encrypted data " , " collectd.data.encrypted " , FT_BYTES , BASE_NONE ,
2009-09-15 00:18:40 +00:00
NULL , 0x0 , NULL , HFILL }
} ,
2009-09-14 01:36:26 +00:00
} ;
/* Setup protocol subtree array */
static gint * ett [ ] = {
& ett_collectd ,
& ett_collectd_string ,
& ett_collectd_integer ,
& ett_collectd_part_value ,
& ett_collectd_value ,
& ett_collectd_valinfo ,
2009-09-15 00:18:40 +00:00
& ett_collectd_signature ,
& ett_collectd_encryption ,
2009-09-14 01:36:26 +00:00
& ett_collectd_dispatch ,
& ett_collectd_invalid_length ,
& ett_collectd_unknown ,
} ;
2013-09-01 13:05:27 +00:00
static ei_register_info ei [ ] = {
{ & ei_collectd_invalid_length , { " collectd.invalid_length " , PI_MALFORMED , PI_ERROR , " Invalid length " , EXPFILL } } ,
{ & ei_collectd_garbage , { " collectd.garbage " , PI_MALFORMED , PI_ERROR , " Garbage at end of packet " , EXPFILL } } ,
{ & 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 } } ,
{ & ei_collectd_type , { " collectd.type.unknown " , PI_UNDECODED , PI_NOTE , " Unknown part type " , EXPFILL } } ,
} ;
2009-09-14 01:36:26 +00:00
/* Register the protocol name and description */
2013-09-01 13:05:27 +00:00
proto_collectd = proto_register_protocol ( " collectd network data " , " collectd " , " collectd " ) ;
2009-09-14 01:36:26 +00:00
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array ( proto_collectd , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
2013-09-01 13:05:27 +00:00
expert_collectd = expert_register_protocol ( proto_collectd ) ;
expert_register_field_array ( expert_collectd , ei , array_length ( ei ) ) ;
2009-09-14 01:36:26 +00:00
2009-09-15 01:34:01 +00:00
tap_collectd = register_tap ( " collectd " ) ;
2009-09-14 01:36:26 +00:00
/*
* Create an unsigned integer preference to allow the user to specify the
* UDP port on which to capture DIS packets .
*/
collectd_module = prefs_register_protocol ( proto_collectd ,
proto_reg_handoff_collectd ) ;
prefs_register_uint_preference ( collectd_module , " udp.port " ,
" collectd UDP port " ,
" Set the UDP port for collectd messages " ,
10 , & collectd_udp_port ) ;
} /* void proto_register_collectd */
void proto_reg_handoff_collectd ( void )
{
static gboolean first_run = TRUE ;
static gint registered_udp_port = - 1 ;
static dissector_handle_t collectd_handle ;
if ( first_run )
collectd_handle = create_dissector_handle ( dissect_collectd ,
proto_collectd ) ;
/* Change the dissector registration if the preferences have been
* changed . */
if ( registered_udp_port ! = - 1 )
2010-12-20 05:35:29 +00:00
dissector_delete_uint ( " udp.port " , registered_udp_port ,
2009-09-14 01:36:26 +00:00
collectd_handle ) ;
2010-12-20 05:35:29 +00:00
dissector_add_uint ( " udp.port " , collectd_udp_port , collectd_handle ) ;
2009-09-14 01:36:26 +00:00
registered_udp_port = collectd_udp_port ;
2009-09-15 01:34:01 +00:00
if ( first_run )
collectd_stats_tree_register ( ) ;
2009-09-14 01:36:26 +00:00
first_run = FALSE ;
} /* void proto_reg_handoff_collectd */
2014-10-02 21:47:19 +00:00
/*
* Editor modelines - http : //www.wireshark.org/tools/modelines.html
*
* Local variables :
* c - basic - offset : 8
* tab - width : 8
* indent - tabs - mode : t
* End :
*
* vi : set shiftwidth = 8 tabstop = 8 noexpandtab :
* : indentSize = 8 : tabSize = 8 : noTabs = false :
*/