2 * dcerpc_stat 2002 Ronnie Sahlberg
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 /* This module provides rpc call/reply SRT statistics to Wireshark,
26 * and displays them graphically.
27 * It is only used by Wireshark and not tshark
29 * It serves as an example on how to use the tap api.
40 #include <epan/packet_info.h>
41 #include <epan/epan.h>
43 #include <epan/stat_cmd_args.h>
44 #include "../stat_menu.h"
45 #include "gui_stat_menu.h"
46 #include "simple_dialog.h"
47 #include "dlg_utils.h"
48 #include "gui_utils.h"
50 #include "../register.h"
51 #include <epan/dissectors/packet-dcerpc.h>
52 #include "../globals.h"
53 #include "filter_dlg.h"
54 #include "compat_macros.h"
55 #include "service_response_time_table.h"
56 #include "gtkglobals.h"
59 /* used to keep track of the statistics for an entire program interface */
60 typedef struct _rpcstat_t {
62 srt_stat_table srt_table;
71 uuid_equal(e_uuid_t *uuid1, e_uuid_t *uuid2)
73 if( (uuid1->Data1!=uuid2->Data1)
74 ||(uuid1->Data2!=uuid2->Data2)
75 ||(uuid1->Data3!=uuid2->Data3)
76 ||(uuid1->Data4[0]!=uuid2->Data4[0])
77 ||(uuid1->Data4[1]!=uuid2->Data4[1])
78 ||(uuid1->Data4[2]!=uuid2->Data4[2])
79 ||(uuid1->Data4[3]!=uuid2->Data4[3])
80 ||(uuid1->Data4[4]!=uuid2->Data4[4])
81 ||(uuid1->Data4[5]!=uuid2->Data4[5])
82 ||(uuid1->Data4[6]!=uuid2->Data4[6])
83 ||(uuid1->Data4[7]!=uuid2->Data4[7]) ){
90 dcerpcstat_gen_title(rpcstat_t *rs)
94 title = g_strdup_printf("DCE-RPC Service Response Time statistics for %s major version %u: %s", rs->prog, rs->ver, cf_get_display_name(&cfile));
99 dcerpcstat_set_title(rpcstat_t *rs)
103 title = dcerpcstat_gen_title(rs);
104 gtk_window_set_title(GTK_WINDOW(rs->win), title);
109 dcerpcstat_reset(void *rs_arg)
111 rpcstat_t *rs = rs_arg;
113 reset_srt_table_data(&rs->srt_table);
114 dcerpcstat_set_title(rs);
119 dcerpcstat_packet(void *rs_arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ri_arg)
121 rpcstat_t *rs = rs_arg;
122 const dcerpc_info *ri = ri_arg;
127 if(!ri->call_data->req_frame){
128 /* we have not seen the request so we dont know the delta*/
131 if(ri->call_data->opnum>=rs->num_procedures){
132 /* dont handle this since its outside of known table */
136 /* we are only interested in reply packets */
137 if(ri->ptype != PDU_RESP){
141 /* we are only interested in certain program/versions */
142 if( (!uuid_equal( (&ri->call_data->uuid), (&rs->uuid)))
143 ||(ri->call_data->ver!=rs->ver)){
148 add_srt_table_data(&rs->srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
155 dcerpcstat_draw(void *rs_arg)
157 rpcstat_t *rs = rs_arg;
159 draw_srt_table_data(&rs->srt_table);
163 /* since the gtk2 implementation of tap is multithreaded we must protect
164 * remove_tap_listener() from modifying the list while draw_tap_listener()
165 * is running. the other protected block is in main.c
167 * there should not be any other critical regions in gtk2
169 void protect_thread_critical_region(void);
170 void unprotect_thread_critical_region(void);
172 win_destroy_cb(GtkWindow *win _U_, gpointer data)
174 rpcstat_t *rs=(rpcstat_t *)data;
176 protect_thread_critical_region();
177 remove_tap_listener(rs);
178 unprotect_thread_critical_region();
180 free_srt_table_data(&rs->srt_table);
186 /* When called, this function will create a new instance of gtk-dcerpcstat.
189 gtk_dcerpcstat_init(const char *optarg, void* userdata _U_)
192 guint32 i, max_procs;
194 char filter_string[256];
196 GtkWidget *stat_label;
197 GtkWidget *filter_label;
200 dcerpc_sub_dissector *procs;
202 guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
206 const char *filter=NULL;
207 GString *error_string;
211 * XXX - DCE RPC statistics are maintained only by major version,
212 * not by major and minor version, so the minor version number is
215 * Should we just stop supporting minor version numbers here?
216 * Or should we allow it to be omitted? Or should we keep
217 * separate statistics for different minor version numbers,
218 * and allow the minor version number to be omitted, and
219 * report aggregate statistics for all minor version numbers
222 if(sscanf(optarg,"dcerpc,srt,%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){
240 fprintf(stderr, "wireshark: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
243 if (major < 0 || major > 65535) {
244 fprintf(stderr,"wireshark: dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535\n", major);
247 if (minor < 0 || minor > 65535) {
248 fprintf(stderr,"wireshark: dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535\n", minor);
253 rs=g_malloc(sizeof(rpcstat_t));
254 rs->prog=dcerpc_get_proto_name(&uuid, ver);
257 fprintf(stderr,"wireshark: 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);
260 hf_opnum=dcerpc_get_proto_hf_opnum(&uuid, ver);
261 procs=dcerpc_get_proto_sub_dissector(&uuid, ver);
265 rs->win=window_new(GTK_WINDOW_TOPLEVEL, "dcerpc-stat");
266 dcerpcstat_set_title(rs);
267 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
269 vbox=gtk_vbox_new(FALSE, 3);
270 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
271 gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
273 title_string=dcerpcstat_gen_title(rs);
274 stat_label=gtk_label_new(title_string);
275 g_free(title_string);
276 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
278 g_snprintf(filter_string,255,"Filter:%s",filter?filter:"");
279 filter_label=gtk_label_new(filter_string);
280 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
282 for(i=0,max_procs=0;procs[i].name;i++){
283 if(procs[i].num>max_procs){
284 max_procs=procs[i].num;
287 rs->num_procedures=max_procs+1;
289 /* We must display TOP LEVEL Widget before calling init_srt_table() */
290 gtk_widget_show_all(rs->win);
293 init_srt_table(&rs->srt_table, max_procs+1, vbox, proto_registrar_get_nth(hf_opnum)->abbrev);
295 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
298 for(i=0;i<(max_procs+1);i++){
300 const char *proc_name;
303 for(j=0;procs[j].name;j++){
305 proc_name=procs[j].name;
309 init_srt_table_row(&rs->srt_table, i, proc_name);
313 error_string=register_tap_listener("dcerpc", rs, filter, dcerpcstat_reset, dcerpcstat_packet, dcerpcstat_draw);
315 /* error, we failed to attach to the tap. clean up */
316 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
317 g_string_free(error_string, TRUE);
318 free_srt_table_data(&rs->srt_table);
324 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
325 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
327 close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
328 window_set_cancel_button(rs->win, close_bt, window_cancel_button_cb);
330 SIGNAL_CONNECT(rs->win, "delete_event", window_delete_event_cb, NULL);
331 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
333 gtk_widget_show_all(rs->win);
334 window_present(rs->win);
336 cf_retap_packets(&cfile, FALSE);
341 static e_uuid_t *dcerpc_uuid_program=NULL;
342 static guint16 dcerpc_version;
343 static GtkWidget *dlg=NULL;
344 static GtkWidget *prog_menu;
345 static GtkWidget *vers_opt, *vers_menu;
346 static GtkWidget *filter_entry;
347 static dcerpc_uuid_key *current_uuid_key=NULL;
348 static dcerpc_uuid_value *current_uuid_value=NULL;
349 static dcerpc_uuid_key *new_uuid_key=NULL;
350 static dcerpc_uuid_value *new_uuid_value=NULL;
354 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
359 str = g_string_new("dcerpc,srt");
360 g_string_sprintfa(str,
361 ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%u.%u",
362 dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
363 dcerpc_uuid_program->Data3,
364 dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
365 dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
366 dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
367 dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
369 filter=gtk_entry_get_text(GTK_ENTRY(filter_entry));
371 g_string_sprintfa(str, ",%s", filter);
374 gtk_dcerpcstat_init(str->str,NULL);
375 g_string_free(str, TRUE);
380 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
391 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
393 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
394 GtkWidget *menu_item;
397 if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
401 g_snprintf(vs, 5, "%u",k->ver);
402 menu_item=gtk_menu_item_new_with_label(vs);
403 SIGNAL_CONNECT(menu_item, "activate", dcerpcstat_version_select,
405 gtk_widget_show(menu_item);
406 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
408 if(dcerpc_version==0xffff){
409 dcerpc_version=k->ver;
417 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
419 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
421 dcerpc_uuid_program=&k->uuid;
423 /* change version menu */
424 dcerpc_version=0xffff;
425 gtk_object_destroy(GTK_OBJECT(vers_menu));
426 vers_menu=gtk_menu_new();
427 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
428 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
432 static GtkWidget *program_submenu_menu;
433 static GtkWidget *program_submenu_item;
434 static GtkWidget *program_submenu_label;
435 static int program_subitem_index;
436 static const char *first_menu_name;
438 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
440 GtkWidget *program_menu_item;
444 switch(program_subitem_index%15){
447 first_menu_name=v->name;
448 g_snprintf(str,63,"%s ...",v->name);
449 program_submenu_item=gtk_menu_item_new();
450 box=gtk_hbox_new(TRUE,0);
451 gtk_container_add(GTK_CONTAINER(program_submenu_item), box);
453 program_submenu_label=gtk_label_new(str);
454 gtk_box_pack_start(GTK_BOX(box), program_submenu_label, TRUE, TRUE, 0);
455 gtk_widget_show(program_submenu_label);
456 gtk_widget_show(box);
458 gtk_menu_append(GTK_MENU(prog_menu), program_submenu_item);
459 gtk_widget_show(program_submenu_item);
461 program_submenu_menu=gtk_menu_new();
462 gtk_menu_item_set_submenu(GTK_MENU_ITEM(program_submenu_item), program_submenu_menu);
465 g_snprintf(str,63,"%s - %s",first_menu_name,v->name);
466 gtk_label_set_text(GTK_LABEL(program_submenu_label), str);
470 program_subitem_index++;
472 program_menu_item=gtk_menu_item_new_with_label(v->name);
473 SIGNAL_CONNECT(program_menu_item, "activate", dcerpcstat_program_select, k);
475 gtk_widget_show(program_menu_item);
476 gtk_menu_append(GTK_MENU(program_submenu_menu), program_menu_item);
478 if(!dcerpc_uuid_program){
479 dcerpc_uuid_program=&k->uuid;
486 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
488 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
489 dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
491 /* first time called, just set new_uuid to this one */
492 if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
498 /* if we havent got a current one yet, just check the new
499 and scan for the first one alphabetically */
500 if(current_uuid_key==NULL){
501 if(strcmp(new_uuid_value->name, v->name)>0){
509 /* searching for the next one we are only interested in those
510 that sorts alphabetically after the current one */
511 if(strcmp(current_uuid_value->name, v->name)>=0){
512 /* this one doesnt so just skip it */
516 /* is it the first potential new entry? */
517 if(new_uuid_key==NULL){
523 /* does it sort before the current new one? */
524 if(strcmp(new_uuid_value->name, v->name)>0){
542 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
545 GtkWidget *prog_box, *prog_label, *prog_opt;
546 GtkWidget *vers_label;
547 GtkWidget *filter_box, *filter_bt;
548 GtkWidget *bbox, *start_button, *cancel_button;
550 static construct_args_t args = {
551 "Service Response Time Statistics Filter",
557 /* if the window is already open, bring it to front and
558 un-minimize it, as necessary */
560 reactivate_window(dlg);
564 dlg=dlg_window_new("Wireshark: Compute DCE-RPC SRT statistics");
565 gtk_window_set_default_size(GTK_WINDOW(dlg), 400, -1);
567 dlg_box=gtk_vbox_new(FALSE, 10);
568 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
569 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
570 gtk_widget_show(dlg_box);
573 prog_box=gtk_hbox_new(FALSE, 3);
576 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
577 prog_label=gtk_label_new("Program:");
578 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
579 gtk_widget_show(prog_label);
582 prog_opt=gtk_option_menu_new();
583 prog_menu=gtk_menu_new();
584 current_uuid_key=NULL;
585 current_uuid_value=NULL;
587 program_submenu_item=NULL;
588 program_submenu_menu=NULL;
589 program_subitem_index=0;
593 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
595 dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
597 current_uuid_key=new_uuid_key;
598 current_uuid_value=new_uuid_value;
599 } while(new_uuid_key!=NULL);
601 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
602 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
603 gtk_widget_show(prog_opt);
606 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
607 vers_label=gtk_label_new("Version:");
608 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
609 gtk_widget_show(vers_label);
612 vers_opt=gtk_option_menu_new();
613 vers_menu=gtk_menu_new();
614 dcerpc_version=0xffff;
615 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
616 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
617 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
618 gtk_widget_show(vers_opt);
620 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
621 gtk_widget_show(prog_box);
624 filter_box=gtk_hbox_new(FALSE, 3);
627 filter_bt=BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
628 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
629 gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
630 gtk_widget_show(filter_bt);
633 filter_entry=gtk_entry_new();
634 SIGNAL_CONNECT(filter_entry, "changed", filter_te_syntax_check_cb, NULL);
635 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
636 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
638 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
640 gtk_widget_show(filter_entry);
642 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
643 gtk_widget_show(filter_box);
645 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_entry);
648 bbox = dlg_button_row_new(WIRESHARK_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
649 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
650 gtk_widget_show(bbox);
652 start_button = OBJECT_GET_DATA(bbox, WIRESHARK_STOCK_CREATE_STAT);
653 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
654 dcerpcstat_start_button_clicked, NULL);
656 cancel_button = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
657 window_set_cancel_button(dlg, cancel_button, window_cancel_button_cb);
659 SIGNAL_CONNECT(dlg, "delete_event", window_delete_event_cb, NULL);
660 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
662 /* Catch the "activate" signal on the filter text entry, so that
663 if the user types Return there, we act as if the "Create Stat"
664 button had been selected, as happens if Return is typed if some
665 widget that *doesn't* handle the Return key has the input
667 dlg_set_activate(filter_entry, start_button);
669 gtk_widget_grab_default(start_button );
671 /* Give the initial focus to the "Filter" entry box. */
672 gtk_widget_grab_focus(filter_entry);
674 gtk_widget_show_all(dlg);
679 register_tap_listener_gtkdcerpcstat(void)
681 register_stat_cmd_arg("dcerpc,srt,", gtk_dcerpcstat_init,NULL);
683 register_stat_menu_item("DCE-RPC...", REGISTER_STAT_GROUP_RESPONSE_TIME,
684 gtk_dcerpcstat_cb, NULL, NULL, NULL);