sec_vt_header: dissect cont_id + opnum
[wireshark-wip.git] / ui / tap-sequence-analysis.c
blob82dbb998a453e2bbbbc7a3efb706209f418eeecf
1 /* tap-sequence-analysis.c
2 * Flow sequence analysis
4 * $Id$
6 * Some code from from gtk/flow_graph.c
7 *
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "config.h"
29 #include "file.h"
31 #include "tap-sequence-analysis.h"
33 #include "epan/addr_resolv.h"
34 #include "epan/column-utils.h"
35 #include "epan/packet.h"
36 #include "epan/tap.h"
37 #include "epan/dissectors/packet-tcp.h"
39 #include "ui/alert_box.h"
41 #include <wsutil/file_util.h>
43 #define NODE_OVERFLOW MAX_NUM_NODES+1
45 #define NODE_CHARS_WIDTH 20
46 #define CONV_TIME_HEADER "Conv.| Time "
47 #define TIME_HEADER "|Time "
48 #define CONV_TIME_EMPTY_HEADER " | "
49 #define TIME_EMPTY_HEADER "| "
50 #define CONV_TIME_HEADER_LENGTH 16
51 #define TIME_HEADER_LENGTH 10
53 /****************************************************************************/
54 /* whenever a frame packet is seen by the tap listener */
55 /* Add a new frame into the graph */
56 static gboolean
57 seq_analysis_frame_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *dummy _U_)
59 seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr;
61 if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){
62 int i;
63 gchar *protocol = NULL;
64 gchar *colinfo = NULL;
65 seq_analysis_item_t *sai = NULL;
67 if (sainfo->any_addr) {
68 if (pinfo->net_src.type!=AT_NONE && pinfo->net_dst.type!=AT_NONE) {
69 sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t));
70 COPY_ADDRESS(&(sai->src_addr),&(pinfo->net_src));
71 COPY_ADDRESS(&(sai->dst_addr),&(pinfo->net_dst));
74 } else {
75 if (pinfo->src.type!=AT_NONE && pinfo->dst.type!=AT_NONE) {
76 sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t));
77 COPY_ADDRESS(&(sai->src_addr),&(pinfo->src));
78 COPY_ADDRESS(&(sai->dst_addr),&(pinfo->dst));
82 if (!sai) return FALSE;
84 sai->fd = pinfo->fd;
86 sai->port_src=pinfo->srcport;
87 sai->port_dst=pinfo->destport;
89 if(pinfo->cinfo) {
90 if (pinfo->cinfo->col_first[COL_INFO]>=0){
92 for (i = pinfo->cinfo->col_first[COL_INFO]; i <= pinfo->cinfo->col_last[COL_INFO]; i++) {
93 if (pinfo->cinfo->fmt_matx[i][COL_INFO]) {
94 colinfo = g_strdup(pinfo->cinfo->col_data[i]);
95 /* break; ? or g_free(colinfo); before g_strdup() */
100 if (pinfo->cinfo->col_first[COL_PROTOCOL]>=0){
102 for (i = pinfo->cinfo->col_first[COL_PROTOCOL]; i <= pinfo->cinfo->col_last[COL_PROTOCOL]; i++) {
103 if (pinfo->cinfo->fmt_matx[i][COL_PROTOCOL]) {
104 protocol = g_strdup(pinfo->cinfo->col_data[i]);
105 /* break; ? or g_free(protocol); before g_strdup() */
111 if (colinfo != NULL) {
112 if (protocol != NULL) {
113 sai->frame_label = g_strdup(colinfo);
114 sai->comment = g_strdup_printf("%s: %s", protocol, colinfo);
115 } else {
116 sai->frame_label = g_strdup(colinfo);
117 sai->comment = g_strdup(colinfo);
119 } else {
120 /* This will probably never happen...*/
121 if (protocol != NULL) {
122 sai->frame_label = g_strdup(protocol);
123 sai->comment = g_strdup(protocol);
127 g_free(protocol);
128 g_free(colinfo);
130 sai->line_style=1;
131 sai->conv_num=0;
132 sai->display=TRUE;
134 sainfo->list = g_list_prepend(sainfo->list, sai);
137 return TRUE;
140 /****************************************************************************/
141 /* whenever a TCP packet is seen by the tap listener */
142 /* Add a new tcp frame into the graph */
143 static gboolean
144 seq_analysis_tcp_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *tcp_info)
146 seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr;
147 const struct tcpheader *tcph = (struct tcpheader *)tcp_info;
149 if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){
150 /* copied from packet-tcp */
151 static const gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR" };
152 guint i, bpos;
153 gboolean flags_found = FALSE;
154 gchar flags[64];
155 seq_analysis_item_t *sai;
157 sai = (seq_analysis_item_t *)g_malloc0(sizeof(seq_analysis_item_t));
158 sai->fd = pinfo->fd;
159 if (sainfo->any_addr) {
160 COPY_ADDRESS(&(sai->src_addr),&(pinfo->net_src));
161 COPY_ADDRESS(&(sai->dst_addr),&(pinfo->net_dst));
162 } else {
163 COPY_ADDRESS(&(sai->src_addr),&(pinfo->src));
164 COPY_ADDRESS(&(sai->dst_addr),&(pinfo->dst));
166 sai->port_src=pinfo->srcport;
167 sai->port_dst=pinfo->destport;
169 flags[0] = '\0';
170 for (i = 0; i < 8; i++) {
171 bpos = 1 << i;
172 if (tcph->th_flags & bpos) {
173 if (flags_found) {
174 g_strlcat(flags, ", ", sizeof(flags));
176 g_strlcat(flags, fstr[i], sizeof(flags));
177 flags_found = TRUE;
180 if (flags[0] == '\0') {
181 g_snprintf (flags, sizeof(flags), "<None>");
184 if ((tcph->th_have_seglen)&&(tcph->th_seglen!=0)){
185 sai->frame_label = g_strdup_printf("%s - Len: %u",flags, tcph->th_seglen);
187 else{
188 sai->frame_label = g_strdup(flags);
191 if (tcph->th_flags & TH_ACK)
192 sai->comment = g_strdup_printf("Seq = %u Ack = %u",tcph->th_seq, tcph->th_ack);
193 else
194 sai->comment = g_strdup_printf("Seq = %u",tcph->th_seq);
196 sai->line_style = 1;
197 sai->conv_num = 0;
198 sai->display = TRUE;
200 sainfo->list = g_list_prepend(sainfo->list, sai);
203 return TRUE;
206 void
207 sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo)
209 GList *list;
210 gchar time_str[COL_MAX_LEN];
212 if (!cf || !sainfo) return;
214 switch (sainfo->type) {
215 case SEQ_ANALYSIS_ANY:
216 register_tap_listener("frame", sainfo, NULL,
217 TL_REQUIRES_COLUMNS,
218 NULL,
219 seq_analysis_frame_packet,
220 NULL
222 break;
223 case SEQ_ANALYSIS_TCP:
224 register_tap_listener("tcp", sainfo, NULL,
226 NULL,
227 seq_analysis_tcp_packet,
228 NULL
230 break;
231 case SEQ_ANALYSIS_VOIP:
232 default:
233 return;
234 break;
238 cf_retap_packets(cf);
239 sainfo->list = g_list_reverse(sainfo->list);
240 remove_tap_listener(sainfo);
242 /* Fill in the timestamps */
243 list = g_list_first(sainfo->list);
244 while (list)
246 seq_analysis_item_t *seq_item = (seq_analysis_item_t *)list->data;
247 set_fd_time(cf->epan, seq_item->fd, time_str);
248 seq_item->time_str = g_strdup(time_str);
249 list = g_list_next(list);
253 void
254 sequence_analysis_list_free(seq_analysis_info_t *sainfo)
256 GList *list;
257 int i;
259 if (!sainfo) return;
261 /* free the graph data items */
262 list = g_list_first(sainfo->list);
263 while (list)
265 seq_analysis_item_t *seq_item = (seq_analysis_item_t *)list->data;
266 g_free(seq_item->frame_label);
267 g_free(seq_item->time_str);
268 g_free(seq_item->comment);
269 g_free(list->data);
270 list = g_list_next(list);
272 g_list_free(sainfo->list);
273 sainfo->list = NULL;
274 sainfo->nconv = 0;
276 for (i=0; i<MAX_NUM_NODES; i++) {
277 sainfo->nodes[i].type = AT_NONE;
278 sainfo->nodes[i].len = 0;
279 g_free((void *)sainfo->nodes[i].data);
280 sainfo->nodes[i].data = NULL;
282 sainfo->num_nodes = 0;
285 /****************************************************************************/
286 /* Adds trailing characters to complete the requested length. */
287 /****************************************************************************/
289 static void enlarge_string(GString *gstr, guint32 length, char pad) {
291 gsize i;
293 for (i = gstr->len; i < length; i++) {
294 g_string_append_c(gstr, pad);
298 /****************************************************************************/
299 /* overwrites the characters in a string, between positions p1 and p2, with */
300 /* the characters of text_to_insert */
301 /* NB: it does not check that p1 and p2 fit into string */
302 /****************************************************************************/
304 static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 p2) {
306 glong len, ins_len;
307 gsize pos;
308 gchar *ins_str = NULL;
310 if (p1 == p2)
311 return;
313 if (p1 > p2) {
314 pos = p2;
315 len = p1 - p2;
317 else{
318 pos = p1;
319 len = p2 - p1;
322 ins_len = g_utf8_strlen(text_to_insert, -1);
323 if (len > ins_len) {
324 len = ins_len;
325 } else if (len < ins_len) {
326 #if GLIB_CHECK_VERSION(2,30,0)
327 ins_str = g_utf8_substring(text_to_insert, 0, len);
328 #else
329 gchar *end = g_utf8_offset_to_pointer(text_to_insert, len);
330 ins_str = g_strndup(text_to_insert, end - text_to_insert);
331 #endif
334 if (!ins_str) ins_str = g_strdup(text_to_insert);
336 if (pos > gstr->len)
337 pos = gstr->len;
339 g_string_erase(gstr, pos, len);
341 g_string_insert(gstr, pos, ins_str);
342 g_free(ins_str);
345 /* Return the index array if the node is in the array. Return -1 if there is room in the array
346 * and Return -2 if the array is full
348 /****************************************************************************/
349 static gint add_or_get_node(seq_analysis_info_t *sainfo, address *node) {
350 guint i;
352 if (node->type == AT_NONE) return NODE_OVERFLOW;
354 for (i=0; i<MAX_NUM_NODES && i < sainfo->num_nodes ; i++) {
355 if ( CMP_ADDRESS(&(sainfo->nodes[i]), node) == 0 ) return i; /* it is in the array */
358 if (i == MAX_NUM_NODES) {
359 return NODE_OVERFLOW;
360 } else {
361 sainfo->num_nodes++;
362 COPY_ADDRESS(&(sainfo->nodes[i]), node);
363 return i;
367 /* Get the nodes from the list */
368 /****************************************************************************/
370 sequence_analysis_get_nodes(seq_analysis_info_t *sainfo)
372 GList *list;
373 seq_analysis_item_t *gai;
374 int num_items = 0;
376 /* fill the node array */
377 list = g_list_first(sainfo->list);
378 while (list)
380 gai = (seq_analysis_item_t *)list->data;
381 if (gai->display) {
382 num_items++;
383 #if 0 /* inverse is always false ? */
384 if (!user_data->dlg.inverse) {
385 #endif
386 gai->src_node = (guint16)add_or_get_node(sainfo, &(gai->src_addr));
387 gai->dst_node = (guint16)add_or_get_node(sainfo, &(gai->dst_addr));
388 #if 0 /* inverse is always false ? */
389 } else {
390 gai->dst_node = (guint16)add_or_get_node(sainfo, &(gai->src_addr));
391 gai->src_node = (guint16)add_or_get_node(sainfo, &(gai->dst_addr));
393 #endif
395 list = g_list_next(list);
397 return num_items;
400 /****************************************************************************/
401 gboolean
402 sequence_analysis_dump_to_file(const char *pathname, seq_analysis_info_t *sainfo, capture_file *cf, unsigned int first_node)
404 guint32 i, display_items, display_nodes;
405 guint32 start_position, end_position, item_width, header_length;
406 seq_analysis_item_t *sai;
407 guint16 first_conv_num = 0;
408 gboolean several_convs = FALSE;
409 gboolean first_packet = TRUE;
411 GString *label_string, *empty_line, *separator_line, *tmp_str, *tmp_str2;
412 const char *empty_header;
413 char src_port[8], dst_port[8];
414 gchar *time_str;
415 GList *list;
417 FILE *of;
419 of = ws_fopen(pathname, "w");
420 if (of==NULL) {
421 open_failure_alert_box(pathname, errno, TRUE);
422 return FALSE;
425 time_str = (gchar *)g_malloc(COL_MAX_LEN);
426 label_string = g_string_new("");
427 empty_line = g_string_new("");
428 separator_line = g_string_new("");
429 tmp_str = g_string_new("");
430 tmp_str2 = g_string_new("");
432 display_items = 0;
433 list = g_list_first(sainfo->list);
434 while (list)
436 sai = (seq_analysis_item_t *)list->data;
437 list = g_list_next(list);
439 if (!sai->display)
440 continue;
442 display_items += 1;
443 if (first_packet) {
444 first_conv_num = sai->conv_num;
445 first_packet = FALSE;
447 else if (sai->conv_num != first_conv_num) {
448 several_convs = TRUE;
452 /* if not items to display */
453 if (display_items == 0)
454 goto exit;
456 display_nodes = sainfo->num_nodes;
458 /* Write the conv. and time headers */
459 if (several_convs) {
460 fprintf(of, CONV_TIME_HEADER);
461 empty_header = CONV_TIME_EMPTY_HEADER;
462 header_length = CONV_TIME_HEADER_LENGTH;
464 else{
465 fprintf(of, TIME_HEADER);
466 empty_header = TIME_EMPTY_HEADER;
467 header_length = TIME_HEADER_LENGTH;
470 /* Write the node names on top */
471 for (i=0; i<display_nodes; i+=2) {
472 /* print the node identifiers */
473 g_string_printf(label_string, "| %s",
474 get_addr_name(&(sainfo->nodes[i+first_node])));
475 enlarge_string(label_string, NODE_CHARS_WIDTH*2, ' ');
476 fprintf(of, "%s", label_string->str);
477 g_string_printf(label_string, "| ");
478 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
479 g_string_append(empty_line, label_string->str);
482 fprintf(of, "|\n%s", empty_header);
483 g_string_printf(label_string, "| ");
484 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
485 fprintf(of, "%s", label_string->str);
487 /* Write the node names on top */
488 for (i=1; i<display_nodes; i+=2) {
489 /* print the node identifiers */
490 g_string_printf(label_string, "| %s",
491 get_addr_name(&(sainfo->nodes[i+first_node])));
492 if (label_string->len < NODE_CHARS_WIDTH)
494 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
495 g_string_append(label_string, "| ");
497 enlarge_string(label_string, NODE_CHARS_WIDTH*2, ' ');
498 fprintf(of, "%s", label_string->str);
499 g_string_printf(label_string, "| ");
500 enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
501 g_string_append(empty_line, label_string->str);
504 fprintf(of, "\n");
506 g_string_append_c(empty_line, '|');
508 enlarge_string(separator_line, (guint32) empty_line->len + header_length, '-');
511 * Draw the items
514 list = g_list_first(sainfo->list);
515 while (list)
517 sai = (seq_analysis_item_t *)list->data;
518 list = g_list_next(list);
520 if (!sai->display)
521 continue;
523 start_position = (sai->src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
525 end_position = (sai->dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
527 if (start_position > end_position) {
528 item_width = start_position-end_position;
530 else if (start_position < end_position) {
531 item_width = end_position-start_position;
533 else{ /* same origin and destination address */
534 end_position = start_position+NODE_CHARS_WIDTH;
535 item_width = NODE_CHARS_WIDTH;
538 /* separator between conversations */
539 if (sai->conv_num != first_conv_num) {
540 fprintf(of, "%s\n", separator_line->str);
541 first_conv_num = sai->conv_num;
544 /* write the conversation number */
545 if (several_convs) {
546 g_string_printf(label_string, "%i", sai->conv_num);
547 enlarge_string(label_string, 5, ' ');
548 fprintf(of, "%s", label_string->str);
551 #if 0
552 /* write the time */
553 g_string_printf(label_string, "|%.3f", nstime_to_sec(&sai->fd->rel_ts));
554 #endif
555 /* Write the time, using the same format as in the time col */
556 set_fd_time(cf->epan, sai->fd, time_str);
557 g_string_printf(label_string, "|%s", time_str);
558 enlarge_string(label_string, 10, ' ');
559 fprintf(of, "%s", label_string->str);
561 /* write the frame label */
563 g_string_printf(tmp_str, "%s", empty_line->str);
564 overwrite(tmp_str, sai->frame_label,
565 start_position,
566 end_position
568 fprintf(of, "%s", tmp_str->str);
570 /* write the comments */
571 fprintf(of, "%s\n", sai->comment);
573 /* write the arrow and frame label*/
574 fprintf(of, "%s", empty_header);
576 g_string_printf(tmp_str, "%s", empty_line->str);
578 g_string_truncate(tmp_str2, 0);
580 if (start_position<end_position) {
581 enlarge_string(tmp_str2, item_width-2, '-');
582 g_string_append_c(tmp_str2, '>');
584 else{
585 g_string_printf(tmp_str2, "<");
586 enlarge_string(tmp_str2, item_width-1, '-');
589 overwrite(tmp_str, tmp_str2->str,
590 start_position,
591 end_position
594 g_snprintf(src_port, sizeof(src_port), "(%i)", sai->port_src);
595 g_snprintf(dst_port, sizeof(dst_port), "(%i)", sai->port_dst);
597 if (start_position<end_position) {
598 overwrite(tmp_str, src_port, start_position-9, start_position-1);
599 overwrite(tmp_str, dst_port, end_position+1, end_position+9);
601 else{
602 overwrite(tmp_str, src_port, start_position+1, start_position+9);
603 overwrite(tmp_str, dst_port, end_position-9, end_position+1);
606 fprintf(of, "%s\n", tmp_str->str);
609 exit:
610 g_string_free(label_string, TRUE);
611 g_string_free(empty_line, TRUE);
612 g_string_free(separator_line, TRUE);
613 g_string_free(tmp_str, TRUE);
614 g_string_free(tmp_str2, TRUE);
615 g_free(time_str);
616 fclose (of);
617 return TRUE;
622 * Editor modelines
624 * Local Variables:
625 * c-basic-offset: 4
626 * tab-width: 8
627 * indent-tabs-mode: nil
628 * End:
630 * ex: set shiftwidth=4 tabstop=8 expandtab:
631 * :indentSize=4:tabSize=8:noTabs=true: