2002-10-23 03:49:13 +00:00
/* tap-dcerpcstat.c
* dcerpcstat 2002 Ronnie Sahlberg
*
2004-07-18 00:24:25 +00:00
* $ Id $
2002-10-23 03:49:13 +00:00
*
2006-05-21 05:12:17 +00:00
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
2002-10-23 03:49:13 +00:00
* Copyright 1998 Gerald Combs
2010-09-23 06:08:19 +00:00
*
2002-10-23 03:49:13 +00:00
* 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 .
2010-09-23 06:08:19 +00:00
*
2002-10-23 03:49:13 +00:00
* 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 .
2010-09-23 06:08:19 +00:00
*
2002-10-23 03:49:13 +00:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <stdio.h>
# ifdef HAVE_SYS_TYPES_H
# include <sys / types.h>
# endif
# include <string.h>
# include "epan/packet_info.h"
2004-09-29 00:06:36 +00:00
# include <epan/tap.h>
2005-08-20 20:06:05 +00:00
# include <epan/stat_cmd_args.h>
2004-07-18 18:06:47 +00:00
# include <epan/dissectors/packet-dcerpc.h>
2002-10-23 03:49:13 +00:00
/* used to keep track of statistics for a specific procedure */
typedef struct _rpc_procedure_t {
2005-07-24 19:01:28 +00:00
const char * proc ;
2002-10-23 03:49:13 +00:00
int num ;
nstime_t min ;
nstime_t max ;
nstime_t tot ;
} rpc_procedure_t ;
/* used to keep track of the statistics for an entire program interface */
typedef struct _rpcstat_t {
2005-07-24 19:01:28 +00:00
const char * prog ;
2002-10-23 03:49:13 +00:00
char * filter ;
e_uuid_t uuid ;
guint16 ver ;
guint32 num_procedures ;
rpc_procedure_t * procedures ;
} rpcstat_t ;
static int
2005-01-01 02:57:02 +00:00
dcerpcstat_packet ( void * prs , packet_info * pinfo , epan_dissect_t * edt _U_ , const void * pri )
2002-10-23 03:49:13 +00:00
{
2005-01-01 02:57:02 +00:00
const dcerpc_info * ri = pri ;
2002-10-31 22:16:01 +00:00
rpcstat_t * rs = prs ;
2002-10-23 03:49:13 +00:00
nstime_t delta ;
rpc_procedure_t * rp ;
if ( ! ri - > call_data ) {
return 0 ;
}
2002-10-25 01:02:49 +00:00
if ( ! ri - > call_data - > req_frame ) {
/* we have not seen the request so we dont know the delta*/
return 0 ;
}
2002-10-23 03:49:13 +00:00
if ( ri - > call_data - > opnum > = rs - > num_procedures ) {
/* dont handle this since its outside of known table */
return 0 ;
}
/* we are only interested in reply packets */
2004-05-07 11:25:15 +00:00
if ( ri - > ptype ! = PDU_RESP ) {
2002-10-23 03:49:13 +00:00
return 0 ;
}
/* we are only interested in certain program/versions */
if ( ( ri - > call_data - > uuid . Data1 ! = rs - > uuid . Data1 )
| | ( ri - > call_data - > uuid . Data2 ! = rs - > uuid . Data2 )
| | ( ri - > call_data - > uuid . Data3 ! = rs - > uuid . Data3 )
| | ( ri - > call_data - > uuid . Data4 [ 0 ] ! = rs - > uuid . Data4 [ 0 ] )
| | ( ri - > call_data - > uuid . Data4 [ 1 ] ! = rs - > uuid . Data4 [ 1 ] )
| | ( ri - > call_data - > uuid . Data4 [ 2 ] ! = rs - > uuid . Data4 [ 2 ] )
| | ( ri - > call_data - > uuid . Data4 [ 3 ] ! = rs - > uuid . Data4 [ 3 ] )
| | ( ri - > call_data - > uuid . Data4 [ 4 ] ! = rs - > uuid . Data4 [ 4 ] )
| | ( ri - > call_data - > uuid . Data4 [ 5 ] ! = rs - > uuid . Data4 [ 5 ] )
| | ( ri - > call_data - > uuid . Data4 [ 6 ] ! = rs - > uuid . Data4 [ 6 ] )
| | ( ri - > call_data - > uuid . Data4 [ 7 ] ! = rs - > uuid . Data4 [ 7 ] )
| | ( ri - > call_data - > ver ! = rs - > ver ) ) {
return 0 ;
}
rp = & ( rs - > procedures [ ri - > call_data - > opnum ] ) ;
/* calculate time delta between request and reply */
2005-08-24 21:31:56 +00:00
nstime_delta ( & delta , & pinfo - > fd - > abs_ts , & ri - > call_data - > req_time ) ;
2002-10-23 03:49:13 +00:00
2003-09-03 10:10:18 +00:00
if ( rp - > num = = 0 ) {
2002-10-23 03:49:13 +00:00
rp - > max . secs = delta . secs ;
rp - > max . nsecs = delta . nsecs ;
}
2003-09-03 10:10:18 +00:00
if ( rp - > num = = 0 ) {
2002-10-23 03:49:13 +00:00
rp - > min . secs = delta . secs ;
rp - > min . nsecs = delta . nsecs ;
}
if ( ( delta . secs < rp - > min . secs )
| | ( ( delta . secs = = rp - > min . secs )
& & ( delta . nsecs < rp - > min . nsecs ) ) ) {
rp - > min . secs = delta . secs ;
rp - > min . nsecs = delta . nsecs ;
}
if ( ( delta . secs > rp - > max . secs )
| | ( ( delta . secs = = rp - > max . secs )
& & ( delta . nsecs > rp - > max . nsecs ) ) ) {
rp - > max . secs = delta . secs ;
rp - > max . nsecs = delta . nsecs ;
}
2010-09-23 06:08:19 +00:00
2002-10-23 03:49:13 +00:00
rp - > tot . secs + = delta . secs ;
rp - > tot . nsecs + = delta . nsecs ;
if ( rp - > tot . nsecs > 1000000000 ) {
rp - > tot . nsecs - = 1000000000 ;
rp - > tot . secs + + ;
}
2003-09-03 10:10:18 +00:00
2002-10-23 03:49:13 +00:00
rp - > num + + ;
return 1 ;
}
static void
2002-10-31 22:16:01 +00:00
dcerpcstat_draw ( void * prs )
2002-10-23 03:49:13 +00:00
{
2002-10-31 22:16:01 +00:00
rpcstat_t * rs = prs ;
2002-10-23 03:49:13 +00:00
guint32 i ;
guint64 td ;
printf ( " \n " ) ;
printf ( " =================================================================== \n " ) ;
2004-01-19 23:43:29 +00:00
printf ( " %s Major Version %u RTT Statistics: \n " , rs - > prog , rs - > ver ) ;
2002-10-23 03:49:13 +00:00
printf ( " Filter: %s \n " , rs - > filter ? rs - > filter : " " ) ;
printf ( " Procedure Calls Min RTT Max RTT Avg RTT \n " ) ;
for ( i = 0 ; i < rs - > num_procedures ; i + + ) {
/* scale it to units of 10us.*/
2007-04-16 04:34:07 +00:00
td = rs - > procedures [ i ] . tot . secs ;
2002-10-23 03:49:13 +00:00
td = td * 100000 + ( int ) rs - > procedures [ i ] . tot . nsecs / 10000 ;
if ( rs - > procedures [ i ] . num ) {
td / = rs - > procedures [ i ] . num ;
} else {
td = 0 ;
}
2007-12-05 10:34:01 +00:00
printf ( " %-25s %6d %3d.%05d %3d.%05d %3 " G_GINT64_MODIFIER " u.%05 " G_GINT64_MODIFIER " u \n " ,
2002-10-23 03:49:13 +00:00
rs - > procedures [ i ] . proc ,
rs - > procedures [ i ] . num ,
( int ) rs - > procedures [ i ] . min . secs , rs - > procedures [ i ] . min . nsecs / 10000 ,
( int ) rs - > procedures [ i ] . max . secs , rs - > procedures [ i ] . max . nsecs / 10000 ,
td / 100000 , td % 100000
) ;
}
printf ( " =================================================================== \n " ) ;
}
2002-10-31 22:16:01 +00:00
static void
2006-02-11 13:05:24 +00:00
dcerpcstat_init ( const char * optarg , void * userdata _U_ )
2002-10-23 03:49:13 +00:00
{
rpcstat_t * rs ;
guint32 i , max_procs ;
dcerpc_sub_dissector * procs ;
2002-10-31 22:16:01 +00:00
e_uuid_t uuid ;
2004-01-19 18:23:01 +00:00
guint d1 , d2 , d3 , d40 , d41 , d42 , d43 , d44 , d45 , d46 , d47 ;
2002-10-31 22:16:01 +00:00
int major , minor ;
2003-12-15 20:15:03 +00:00
guint16 ver ;
2002-10-31 22:16:01 +00:00
int pos = 0 ;
2005-08-06 03:44:55 +00:00
const char * filter = NULL ;
2003-04-23 08:20:06 +00:00
GString * error_string ;
2010-09-23 06:08:19 +00:00
2004-01-19 23:43:29 +00:00
/*
* XXX - DCE RPC statistics are maintained only by major version ,
* not by major and minor version , so the minor version number is
* ignored .
*
* Should we just stop supporting minor version numbers here ?
* Or should we allow it to be omitted ? Or should we keep
* separate statistics for different minor version numbers ,
* and allow the minor version number to be omitted , and
* report aggregate statistics for all minor version numbers
* if it ' s omitted ?
*
* XXX - should this be called " srt " rather than " rtt " ? The
2006-05-22 08:14:01 +00:00
* equivalent tap for Wireshark calls it " srt " , for " Service
2004-01-19 23:43:29 +00:00
* Response Time " , rather than " rtt " for " Round - Trip Time " .
*/
2002-10-31 22:16:01 +00:00
if ( sscanf ( optarg , " dcerpc,rtt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n " , & d1 , & d2 , & d3 , & d40 , & d41 , & d42 , & d43 , & d44 , & d45 , & d46 , & d47 , & major , & minor , & pos ) = = 13 ) {
uuid . Data1 = d1 ;
uuid . Data2 = d2 ;
uuid . Data3 = d3 ;
uuid . Data4 [ 0 ] = d40 ;
uuid . Data4 [ 1 ] = d41 ;
uuid . Data4 [ 2 ] = d42 ;
uuid . Data4 [ 3 ] = d43 ;
uuid . Data4 [ 4 ] = d44 ;
uuid . Data4 [ 5 ] = d45 ;
uuid . Data4 [ 6 ] = d46 ;
uuid . Data4 [ 7 ] = d47 ;
if ( pos ) {
filter = optarg + pos ;
} else {
filter = NULL ;
}
} else {
2006-05-31 17:38:42 +00:00
fprintf ( stderr , " tshark: invalid \" -z dcerpc,rtt,<uuid>,<major version>.<minor version>[,<filter>] \" argument \n " ) ;
2002-10-31 22:16:01 +00:00
exit ( 1 ) ;
}
2004-01-19 23:43:29 +00:00
if ( major < 0 | | major > 65535 ) {
2006-05-31 17:38:42 +00:00
fprintf ( stderr , " tshark: dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535 \n " , major ) ;
2003-12-15 20:15:03 +00:00
exit ( 1 ) ;
}
2004-01-19 23:43:29 +00:00
if ( minor < 0 | | minor > 65535 ) {
2006-05-31 17:38:42 +00:00
fprintf ( stderr , " tshark: dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535 \n " , minor ) ;
2003-12-15 20:15:03 +00:00
exit ( 1 ) ;
}
2004-01-19 23:43:29 +00:00
ver = major ;
2002-10-23 03:49:13 +00:00
rs = g_malloc ( sizeof ( rpcstat_t ) ) ;
2003-12-15 20:15:03 +00:00
rs - > prog = dcerpc_get_proto_name ( & uuid , ver ) ;
2002-10-23 03:49:13 +00:00
if ( ! rs - > prog ) {
g_free ( rs ) ;
2006-05-31 17:38:42 +00:00
fprintf ( stderr , " tshark: dcerpcstat_init() Protocol with uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x v%u not supported \n " , uuid . Data1 , uuid . Data2 , uuid . Data3 , uuid . Data4 [ 0 ] , uuid . Data4 [ 1 ] , uuid . Data4 [ 2 ] , uuid . Data4 [ 3 ] , uuid . Data4 [ 4 ] , uuid . Data4 [ 5 ] , uuid . Data4 [ 6 ] , uuid . Data4 [ 7 ] , ver ) ;
2002-10-23 03:49:13 +00:00
exit ( 1 ) ;
}
2003-12-15 20:15:03 +00:00
procs = dcerpc_get_proto_sub_dissector ( & uuid , ver ) ;
2002-10-31 22:16:01 +00:00
rs - > uuid = uuid ;
2003-12-15 20:15:03 +00:00
rs - > ver = ver ;
2002-10-23 03:49:13 +00:00
if ( filter ) {
2008-02-03 15:38:20 +00:00
rs - > filter = g_strdup ( filter ) ;
2002-10-23 03:49:13 +00:00
} else {
rs - > filter = NULL ;
}
for ( i = 0 , max_procs = 0 ; procs [ i ] . name ; i + + ) {
if ( procs [ i ] . num > max_procs ) {
max_procs = procs [ i ] . num ;
}
}
rs - > num_procedures = max_procs + 1 ;
rs - > procedures = g_malloc ( sizeof ( rpc_procedure_t ) * ( rs - > num_procedures + 1 ) ) ;
for ( i = 0 ; i < rs - > num_procedures ; i + + ) {
int j ;
rs - > procedures [ i ] . proc = " unknown " ;
for ( j = 0 ; procs [ j ] . name ; j + + ) {
if ( procs [ j ] . num = = i ) {
rs - > procedures [ i ] . proc = procs [ j ] . name ;
}
}
2010-09-23 06:08:19 +00:00
rs - > procedures [ i ] . num = 0 ;
2002-10-23 03:49:13 +00:00
rs - > procedures [ i ] . min . secs = 0 ;
rs - > procedures [ i ] . min . nsecs = 0 ;
rs - > procedures [ i ] . max . secs = 0 ;
rs - > procedures [ i ] . max . nsecs = 0 ;
rs - > procedures [ i ] . tot . secs = 0 ;
rs - > procedures [ i ] . tot . nsecs = 0 ;
}
2009-06-05 22:42:47 +00:00
error_string = register_tap_listener ( " dcerpc " , rs , filter , 0 , NULL , dcerpcstat_packet , dcerpcstat_draw ) ;
2003-04-23 08:20:06 +00:00
if ( error_string ) {
2002-10-23 03:49:13 +00:00
/* error, we failed to attach to the tap. clean up */
g_free ( rs - > procedures ) ;
g_free ( rs - > filter ) ;
g_free ( rs ) ;
2006-05-31 17:38:42 +00:00
fprintf ( stderr , " tshark: Couldn't register dcerpc,rtt tap: %s \n " ,
2003-04-23 08:20:06 +00:00
error_string - > str ) ;
g_string_free ( error_string , TRUE ) ;
2002-10-23 03:49:13 +00:00
exit ( 1 ) ;
}
}
2002-10-31 22:16:01 +00:00
void
register_tap_listener_dcerpcstat ( void )
{
2006-02-11 13:05:24 +00:00
register_stat_cmd_arg ( " dcerpc,rtt, " , dcerpcstat_init , NULL ) ;
2002-10-31 22:16:01 +00:00
}