diff --git a/diameter/TGPPGmb.xml b/diameter/TGPPGmb.xml index c6fa429cd3..186806c610 100644 --- a/diameter/TGPPGmb.xml +++ b/diameter/TGPPGmb.xml @@ -58,7 +58,7 @@ - + diff --git a/diameter/dictionary.xml b/diameter/dictionary.xml index bd07fd22e2..1535f797f8 100644 --- a/diameter/dictionary.xml +++ b/diameter/dictionary.xml @@ -1943,7 +1943,7 @@ Note: The AVP codes from 800 to 822 are reserved for TS 32.299. - + diff --git a/doc/tshark.pod b/doc/tshark.pod index 8a7cb4e0f4..cc7375c54d 100644 --- a/doc/tshark.pod +++ b/doc/tshark.pod @@ -671,6 +671,49 @@ B<-z "proto,colinfo,nfs.fh.hash && ip.src==1.2.3.4,nfs.fh.hash"> This option can be used multiple times on the command line. +=item B<-z> diameter,avp[,I,I,I,I<...>] + +This option enables extraction of most important diameter fields from large capture files. +Exactly one text line for each diameter message with matched B will be printed. + +Empty diameter command code or '*' can be specified to mach any B + +Example: B<-z diameter,avp> extract default field set from diameter messages. + +Example: B<-z diameter,avp,280> extract default field set from diameter DWR messages. + +Example: B<-z diameter,avp,272> extract default field set from diameter CC messages. + +Extract most important fields from diameter CC messages: + +B + +Following fields will be printed out for each diameter message: + + "frame" Frame number. + "time" Unix time of the frame arrival. + "src" Source address. + "srcport" Source port. + "dst" Destination address. + "dstport" Destination port. + "proto" Constant string 'diameter', which can be used for post processing of tshark output. e.g. grep/sed/awk. + "msgnr" seq. number of diameter message within the frame. E.g. '2' for the third diameter message in the same frame. + "is_request" '0' if message is a request, '1' if message is an answer. + "cmd" diameter.cmd_code, E.g. '272' for credit control messages. + "req_frame" Number of frame where matched request was found or '0'. + "ans_frame" Number of frame where matched answer was found or '0'. + "resp_time" response time in seconds, '0' in case if matched Request/Answer is not found in trace. E.g. in the begin or end of capture. + +B<-z diameter,avp> option is much faster than B<-V -T text> or B<-T pdml> options. + +B<-z diameter,avp> option is more powerful than B<-T field> and B<-z proto,colinfo> options. + +Multiple diameter messages in one frame are supported. + +Several fields with same name within one diameter message are supported, e.g. I or I. + +Note: B option is recommended to suppress default B output. + =item B<-z> rpc,rtt,I,I[,I] Collect call/reply RTT data for I/I. Data collected diff --git a/tap-diameter-avp.c b/tap-diameter-avp.c index f7d8eb35d2..c602d71b8e 100644 --- a/tap-diameter-avp.c +++ b/tap-diameter-avp.c @@ -55,17 +55,19 @@ #include "epan/nstime.h" #include "epan/ftypes/ftypes.h" #include "register.h" -#include +#include "epan/to_str.h" +#include "epan/dissectors/packet-diameter.h" /* used to keep track of the statistics for an entire program interface */ typedef struct _diameteravp_t { guint32 frame; guint32 diammsg_toprocess; + guint32 cmd_code; guint32 req_count; guint32 ans_count; guint32 paired_ans_count; - char* filter; + gchar* filter; } diameteravp_t; /* Copied from proto.c */ @@ -98,13 +100,13 @@ diam_tree_to_csv(proto_node* node, gpointer data) field_info* fi; header_field_info *hfi; if(!node) { - fprintf(stderr,"traverse end: node='%p' data='%p'\n",node,data); + fprintf(stderr,"traverse end: empty node. node='%p' data='%p'\n",node,data); return FALSE; } fi=node->finfo; hfi=fi ? fi->hfinfo : NULL; if(!hfi) { - fprintf(stderr,"traverse end2: Hfi not found node='%p'\n",node); + fprintf(stderr,"traverse end: hfi not found. node='%p'\n",node); return FALSE; } ftype=fi->value.ftype->ftype; @@ -144,32 +146,39 @@ diameteravp_packet(void *pds, packet_info *pinfo, epan_dissect_t *edt _U_, const header_field_info* hfi=NULL; field_info* finfo=NULL; const diameter_req_ans_pair_t* dp=pdi; + diameteravp_t *ds=NULL; + + /* Validate paramerers. */ + if(!dp || !edt || !edt->tree) + return ret; /* Several diameter messages within one frame are possible. * * Check if we processing the message in same frame like befor or in new frame.*/ - diameteravp_t *ds=(diameteravp_t *)pds; + ds=(diameteravp_t *)pds; if(pinfo->fd->num > ds->frame) { ds->frame=pinfo->fd->num; ds->diammsg_toprocess=0; } else { ds->diammsg_toprocess+=1; } + /* Extract data from request/answer pair provided by diameter dissector.*/ - if(dp) { - is_request=dp->processing_request; - cmd_code=dp->cmd_code; - result_code=dp->result_code; - req_frame=dp->req_frame; - ans_frame=dp->ans_frame; - if(!is_request) { - nstime_t ns; - nstime_delta(&ns, &pinfo->fd->abs_ts, &dp->req_time); - resp_time=nstime_to_sec(&ns); - resp_time=resp_time<0?0.:resp_time; - } + is_request=dp->processing_request; + cmd_code=dp->cmd_code; + result_code=dp->result_code; + req_frame=dp->req_frame; + ans_frame=dp->ans_frame; + if(!is_request) { + nstime_t ns; + nstime_delta(&ns, &pinfo->fd->abs_ts, &dp->req_time); + resp_time=nstime_to_sec(&ns); + resp_time=resp_time<0?0.:resp_time; } - if (!edt || !edt->tree || cmd_code!=272) + + /* Check command code provided by command line option.*/ + if (ds->cmd_code && ds->cmd_code!=cmd_code) return ret; + /* Loop over top level nodes */ node = edt->tree->first_child; while (node != NULL) { @@ -177,7 +186,7 @@ diameteravp_packet(void *pds, packet_info *pinfo, epan_dissect_t *edt _U_, const node = current->next; finfo=current->finfo; hfi=finfo ? finfo->hfinfo : NULL; - /*fprintf(stderr,"diameteravp_packet %d %p %p node=%p abbrev=%s\n",cmd_code,edt,edt->tree,current,hfi->abbrev);*/ + /*fprintf(stderr,"DEBUG: diameteravp_packet %d %p %p node=%p abbrev=%s\n",cmd_code,edt,edt->tree,current,hfi->abbrev);*/ /* process current diameter subtree in the current frame. */ if(hfi && hfi->abbrev && strcmp(hfi->abbrev,"diameter")==0) { /* Process current diameter message in the frame */ @@ -190,7 +199,8 @@ diameteravp_packet(void *pds, packet_info *pinfo, epan_dissect_t *edt _U_, const ds->paired_ans_count++; } /* Output frame data.*/ - printf("frame='%d' proto='diameter' msgnr='%d' is_request='%d' cmd='%d' req_frame='%d' ans_frame='%d' resp_time='%f' ",pinfo->fd->num,ds->diammsg_toprocess,is_request,cmd_code,req_frame,ans_frame,resp_time); + printf("frame='%d' time='%f' src='%s' srcport='%d' dst='%s' dstport='%d' proto='diameter' msgnr='%d' is_request='%d' cmd='%d' req_frame='%d' ans_frame='%d' resp_time='%f' ", + pinfo->fd->num,nstime_to_sec(&pinfo->fd->abs_ts),ep_address_to_str(&pinfo->src),pinfo->srcport,ep_address_to_str(&pinfo->dst), pinfo->destport,ds->diammsg_toprocess,is_request,cmd_code,req_frame,ans_frame,resp_time); /* Visit selected nodes of one diameter message.*/ tree_traverse_pre_order(current, diam_tree_to_csv, &ds); /* End of message.*/ @@ -216,47 +226,45 @@ static void diameteravp_init(const char *optarg, void* userdata _U_) { diameteravp_t *ds; - char* options=NULL; - char* saveptr=NULL; - char* str=NULL; - int field_count=0; - size_t filter_len=0; - GString *error_string; + gchar* field=NULL; + gchar** tokens; + guint opt_count=0; + guint opt_idx=0; + GString* filter=NULL; + GString* error_string=NULL; ds=g_malloc(sizeof(diameteravp_t)); ds->frame=0; ds->diammsg_toprocess=0; + ds->cmd_code=0; ds->req_count=0; ds->ans_count=0; ds->paired_ans_count=0; - str=NULL; ds->filter=NULL; - options=g_strdup(optarg); - for(str=options;*str;str++) - { - if(*str==',') - field_count++; - } - filter_len=strlen(optarg)+sizeof("diameter")+field_count*sizeof("||diameter."); - ds->filter=g_malloc0(filter_len); - g_strlcat(ds->filter, "diameter", filter_len); + filter=g_string_new("diameter"); -#if defined (_WIN32) - for(str=strtok_s(options+sizeof("diameter,avp"),",",&saveptr);str;str=strtok_s(NULL,",",&saveptr)) -#else - for(str=strtok_r(options+sizeof("diameter,avp"),",",&saveptr);str;str=strtok_r(NULL,",",&saveptr)) -#endif + /* Split command line options. */ + tokens = g_strsplit(optarg,",", 1024); + opt_count=g_strv_length(tokens); + if (opt_count>2) + ds->cmd_code=(guint32)atoi(tokens[2]); + + /* Loop over diameter field names. */ + for(opt_idx=3;opt_idxfilter, "||", filter_len); + g_string_append(filter,"||"); /* Prefix field name with "diameter." by default. */ - if(!strchr(str,'.')) - g_strlcat(ds->filter, "diameter.", filter_len); + if(!strchr(field,'.')) + g_string_append(filter, "diameter."); /* Append field name to the filter. */ - g_strlcat(ds->filter, str, filter_len); + g_string_append(filter, field); } - g_free(options); + g_strfreev(tokens); + ds->filter=g_string_free(filter,FALSE); error_string=register_tap_listener("diameter", ds, ds->filter, 0, NULL, diameteravp_packet, diameteravp_draw); if(error_string){