2 * Copyright 2010 Andrej Kuehnal <andrejk@freenet.de>
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * This TAP enables extraction of most important diameter fields in text format.
25 * - much more performance than -T text and -T pdml
26 * - more powerful than -T field and -z proto,colinfo
27 * - exacltly one text line per diameter message
28 * - multiple diameter messages in one frame supported
29 * E.g. one device watchdog answer and two credit control answers
30 * in one TCP packet produces 3 text lines.
31 * - several fields with same name within one diameter message supported
32 * E.g. Multiple AVP(444) Subscription-Id-Data once with IMSI once with MSISDN
33 * - several grouped AVPs supported
34 * E.g. Zero or more Multiple-Services-Credit-Control AVPs(456)
45 #include <epan/packet_info.h>
47 #include <epan/epan_dissect.h>
48 #include <epan/stat_tap_ui.h>
49 #include <epan/value_string.h>
50 #include <epan/to_str.h>
51 #include <epan/dissectors/packet-diameter.h>
53 void register_tap_listener_diameteravp(void);
55 /* used to keep track of the statistics for an entire program interface */
56 typedef struct _diameteravp_t {
58 guint32 diammsg_toprocess;
62 guint32 paired_ans_count;
66 /* Copied from proto.c */
68 tree_traverse_pre_order(proto_tree *tree, proto_tree_traverse_func func, gpointer data)
70 proto_node *pnode = tree;
74 if (func(pnode, data))
77 child = pnode->first_child;
78 while (child != NULL) {
80 child = current->next;
81 if (tree_traverse_pre_order((proto_tree *)current, func, data))
88 diam_tree_to_csv(proto_node *node, gpointer data)
94 header_field_info *hfi;
97 fprintf(stderr, "traverse end: empty node. node='%p' data='%p'\n", (void *)node, (void *)data);
101 hfi = fi ? fi->hfinfo : NULL;
103 fprintf(stderr, "traverse end: hfi not found. node='%p'\n", (void *)node);
106 ftype = fvalue_type_ftenum(&fi->value);
107 if (ftype != FT_NONE && ftype != FT_PROTOCOL) {
108 /* convert value to string */
109 val_tmp = fvalue_to_string_repr(&fi->value, FTREPR_DISPLAY, hfi->display, NULL);
112 val_str = g_strdup(val_tmp);
115 val_str = g_strdup_printf("unsupported type: %s", ftype_name(ftype));
117 /*printf("traverse: name='%s', abbrev='%s',desc='%s', val='%s'\n", hfi->name, hfi->abbrev, ftype_name(hfi->type), val_str);*/
118 printf("%s='%s' ", hfi->name, val_str);
125 diameteravp_packet(void *pds, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pdi)
128 double resp_time = 0.;
129 gboolean is_request = TRUE;
130 guint32 cmd_code = 0;
131 guint32 req_frame = 0;
132 guint32 ans_frame = 0;
133 guint32 diam_child_node = 0;
134 proto_node *current = NULL;
135 proto_node *node = NULL;
136 header_field_info *hfi = NULL;
137 field_info *finfo = NULL;
138 const diameter_req_ans_pair_t *dp = (const diameter_req_ans_pair_t *)pdi;
139 diameteravp_t *ds = NULL;
141 /* Validate paramerers. */
142 if (!dp || !edt || !edt->tree)
145 /* Several diameter messages within one frame are possible. *
146 * Check if we processing the message in same frame like befor or in new frame.*/
147 ds = (diameteravp_t *)pds;
148 if (pinfo->num > ds->frame) {
149 ds->frame = pinfo->num;
150 ds->diammsg_toprocess = 0;
152 ds->diammsg_toprocess += 1;
155 /* Extract data from request/answer pair provided by diameter dissector.*/
156 is_request = dp->processing_request;
157 cmd_code = dp->cmd_code;
158 req_frame = dp->req_frame;
159 ans_frame = dp->ans_frame;
162 nstime_delta(&ns, &pinfo->abs_ts, &dp->req_time);
163 resp_time = nstime_to_sec(&ns);
164 resp_time = resp_time < 0. ? 0. : resp_time;
167 /* Check command code provided by command line option.*/
168 if (ds->cmd_code && ds->cmd_code != cmd_code)
171 /* Loop over top level nodes */
172 node = edt->tree->first_child;
173 while (node != NULL) {
175 node = current->next;
176 finfo = current->finfo;
177 hfi = finfo ? finfo->hfinfo : NULL;
178 /*fprintf(stderr, "DEBUG: diameteravp_packet %d %p %p node=%p abbrev=%s\n", cmd_code, edt, edt->tree, current, hfi->abbrev);*/
179 /* process current diameter subtree in the current frame. */
180 if (hfi && hfi->abbrev && strcmp(hfi->abbrev, "diameter") == 0) {
181 /* Process current diameter message in the frame */
182 if (ds->diammsg_toprocess == diam_child_node) {
188 ds->paired_ans_count++;
190 /* Output frame data.*/
191 printf("frame='%u' time='%f' src='%s' srcport='%u' dst='%s' dstport='%u' proto='diameter' msgnr='%u' is_request='%d' cmd='%u' req_frame='%u' ans_frame='%u' resp_time='%f' ",
192 pinfo->num, nstime_to_sec(&pinfo->abs_ts), address_to_str(pinfo->pool, &pinfo->src), pinfo->srcport, address_to_str(pinfo->pool, &pinfo->dst), pinfo->destport, ds->diammsg_toprocess, is_request, cmd_code, req_frame, ans_frame, resp_time);
193 /* Visit selected nodes of one diameter message.*/
194 tree_traverse_pre_order(current, diam_tree_to_csv, &ds);
197 /*printf("hfi: name='%s', msg_curr='%d' abbrev='%s',type='%s'\n", hfi->name, diam_child_node, hfi->abbrev, ftype_name(hfi->type));*/
206 diameteravp_draw(void *pds)
208 diameteravp_t *ds = (diameteravp_t *)pds;
209 /* printing results */
210 printf("=== Diameter Summary ===\nrequset count:\t%u\nanswer count:\t%u\nreq/ans pairs:\t%u\n", ds->req_count, ds->ans_count, ds->paired_ans_count);
215 diameteravp_init(const char *opt_arg, void *userdata _U_)
222 GString *filter = NULL;
223 GString *error_string = NULL;
225 ds = g_new(diameteravp_t, 1);
227 ds->diammsg_toprocess = 0;
231 ds->paired_ans_count = 0;
234 filter = g_string_new("diameter");
236 /* Split command line options. */
237 tokens = g_strsplit(opt_arg, ",", 1024);
239 while (tokens[opt_count])
242 ds->cmd_code = (guint32)atoi(tokens[2]);
244 /* Loop over diameter field names. */
245 for (opt_idx=3; opt_idx<opt_count; opt_idx++)
247 /* Current field from command line arguments. */
248 field = tokens[opt_idx];
249 /* Connect all requested fields with logical OR. */
250 g_string_append(filter, "||");
251 /* Prefix field name with "diameter." by default. */
252 if (!strchr(field, '.'))
253 g_string_append(filter, "diameter.");
254 /* Append field name to the filter. */
255 g_string_append(filter, field);
258 ds->filter = g_string_free(filter, FALSE);
260 error_string = register_tap_listener("diameter", ds, ds->filter, 0, NULL, diameteravp_packet, diameteravp_draw);
262 /* error, we failed to attach to the tap. clean up */
265 fprintf(stderr, "tshark: Couldn't register diam,csv tap: %s\n",
267 g_string_free(error_string, TRUE);
272 static stat_tap_ui diameteravp_ui = {
273 REGISTER_STAT_GROUP_GENERIC,
282 register_tap_listener_diameteravp(void)
284 register_stat_tap_ui(&diameteravp_ui, NULL);
289 * Editor modelines - http://www.wireshark.org/tools/modelines.html
294 * indent-tabs-mode: t
297 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
298 * :indentSize=8:tabSize=8:noTabs=false: