packet-smb2: fix lease epoch fields
[metze/wireshark/wip.git] / ui / tap-sequence-analysis.c
1 /* tap-sequence-analysis.c
2  * Flow sequence analysis
3  *
4  * $Id$
5  *
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
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 #include "config.h"
28
29 #include "file.h"
30
31 #include "tap-sequence-analysis.h"
32
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"
38
39 #include "ui/alert_box.h"
40
41 #include <wsutil/file_util.h>
42
43 #define NODE_OVERFLOW MAX_NUM_NODES+1
44
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
52
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_)
58 {
59     seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr;
60
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;
66
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));
72             }
73
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));
79             }
80         }
81
82         if (!sai) return FALSE;
83
84         sai->fd = pinfo->fd;
85
86         sai->port_src=pinfo->srcport;
87         sai->port_dst=pinfo->destport;
88
89         if(pinfo->cinfo) {
90             if (pinfo->cinfo->col_first[COL_INFO]>=0){
91
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() */
96                     }
97                 }
98             }
99
100             if (pinfo->cinfo->col_first[COL_PROTOCOL]>=0){
101
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() */
106                     }
107                 }
108             }
109         }
110
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);
118             }
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);
124             }
125         }
126
127         g_free(protocol);
128         g_free(colinfo);
129
130         sai->line_style=1;
131         sai->conv_num=0;
132         sai->display=TRUE;
133
134         sainfo->list = g_list_prepend(sainfo->list, sai);
135     }
136
137     return TRUE;
138 }
139
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)
145 {
146     seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr;
147     const struct tcpheader *tcph = (const struct tcpheader *)tcp_info;
148
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;
156
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));
165         }
166         sai->port_src=pinfo->srcport;
167         sai->port_dst=pinfo->destport;
168
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));
175                 }
176                 g_strlcat(flags, fstr[i], sizeof(flags));
177                 flags_found = TRUE;
178             }
179         }
180         if (flags[0] == '\0') {
181             g_snprintf (flags, sizeof(flags), "<None>");
182         }
183
184         if ((tcph->th_have_seglen)&&(tcph->th_seglen!=0)){
185             sai->frame_label = g_strdup_printf("%s - Len: %u",flags, tcph->th_seglen);
186         }
187         else{
188             sai->frame_label = g_strdup(flags);
189         }
190
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);
195
196         sai->line_style = 1;
197         sai->conv_num = 0;
198         sai->display = TRUE;
199
200         sainfo->list = g_list_prepend(sainfo->list, sai);
201     }
202
203     return TRUE;
204 }
205
206 void
207 sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo)
208 {
209     GList *list;
210     gchar time_str[COL_MAX_LEN];
211
212     if (!cf || !sainfo) return;
213
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
221             );
222         break;
223     case SEQ_ANALYSIS_TCP:
224         register_tap_listener("tcp", sainfo, NULL,
225             0,
226             NULL,
227             seq_analysis_tcp_packet,
228             NULL
229             );
230         break;
231     case SEQ_ANALYSIS_VOIP:
232     default:
233         return;
234         break;
235
236     }
237
238     cf_retap_packets(cf);
239     sainfo->list = g_list_reverse(sainfo->list);
240     remove_tap_listener(sainfo);
241
242     /* Fill in the timestamps */
243     list = g_list_first(sainfo->list);
244     while (list)
245     {
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);
250     }
251 }
252
253 void
254 sequence_analysis_list_free(seq_analysis_info_t *sainfo)
255 {
256     GList *list;
257     int i;
258
259     if (!sainfo) return;
260
261     /* free the graph data items */
262     list = g_list_first(sainfo->list);
263     while (list)
264     {
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);
271     }
272     g_list_free(sainfo->list);
273     sainfo->list = NULL;
274     sainfo->nconv = 0;
275
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;
281     }
282     sainfo->num_nodes = 0;
283 }
284
285 /****************************************************************************/
286 /* Adds trailing characters to complete the requested length.               */
287 /****************************************************************************/
288
289 static void enlarge_string(GString *gstr, guint32 length, char pad) {
290
291     gsize i;
292
293     for (i = gstr->len; i < length; i++) {
294         g_string_append_c(gstr, pad);
295     }
296 }
297
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 /****************************************************************************/
303
304 static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 p2) {
305
306     glong len, ins_len;
307     gsize pos;
308     gchar *ins_str = NULL;
309
310     if (p1 == p2)
311         return;
312
313     if (p1 > p2) {
314         pos = p2;
315         len = p1 - p2;
316     }
317     else{
318         pos = p1;
319         len = p2 - p1;
320     }
321
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
332     }
333
334     if (!ins_str) ins_str = g_strdup(text_to_insert);
335
336     if (pos > gstr->len)
337         pos = gstr->len;
338
339     g_string_erase(gstr, pos, len);
340
341     g_string_insert(gstr, pos, ins_str);
342     g_free(ins_str);
343 }
344
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
347  */
348 /****************************************************************************/
349 static gint add_or_get_node(seq_analysis_info_t *sainfo, address *node) {
350     guint i;
351
352     if (node->type == AT_NONE) return NODE_OVERFLOW;
353
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 */
356     }
357
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;
364     }
365 }
366
367 /* Get the nodes from the list */
368 /****************************************************************************/
369 int
370 sequence_analysis_get_nodes(seq_analysis_info_t *sainfo)
371 {
372     GList *list;
373     seq_analysis_item_t *gai;
374     int num_items = 0;
375
376     /* fill the node array */
377     list = g_list_first(sainfo->list);
378     while (list)
379     {
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));
392             }
393 #endif
394         }
395         list = g_list_next(list);
396     }
397     return num_items;
398 }
399
400 /****************************************************************************/
401 gboolean
402 sequence_analysis_dump_to_file(const char *pathname, seq_analysis_info_t *sainfo, capture_file *cf, unsigned int first_node)
403 {
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;
410
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;
416
417     FILE  *of;
418
419     of = ws_fopen(pathname, "w");
420     if (of==NULL) {
421         open_failure_alert_box(pathname, errno, TRUE);
422         return FALSE;
423     }
424
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("");
431
432     display_items = 0;
433     list = g_list_first(sainfo->list);
434     while (list)
435     {
436         sai = (seq_analysis_item_t *)list->data;
437         list = g_list_next(list);
438
439         if (!sai->display)
440             continue;
441
442         display_items += 1;
443         if (first_packet) {
444             first_conv_num = sai->conv_num;
445             first_packet = FALSE;
446         }
447         else if (sai->conv_num != first_conv_num) {
448             several_convs = TRUE;
449         }
450     }
451
452     /* if not items to display */
453     if (display_items == 0)
454         goto exit;
455
456     display_nodes = sainfo->num_nodes;
457
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;
463     }
464     else{
465         fprintf(of, TIME_HEADER);
466         empty_header = TIME_EMPTY_HEADER;
467         header_length = TIME_HEADER_LENGTH;
468     }
469
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);
480     }
481
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);
486
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)
493         {
494             enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
495             g_string_append(label_string, "| ");
496         }
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);
502     }
503
504     fprintf(of, "\n");
505
506     g_string_append_c(empty_line, '|');
507
508     enlarge_string(separator_line, (guint32) empty_line->len + header_length, '-');
509
510     /*
511      * Draw the items
512      */
513
514     list = g_list_first(sainfo->list);
515     while (list)
516     {
517         sai = (seq_analysis_item_t *)list->data;
518         list = g_list_next(list);
519
520         if (!sai->display)
521             continue;
522
523         start_position = (sai->src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
524
525         end_position = (sai->dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
526
527         if (start_position > end_position) {
528             item_width = start_position-end_position;
529         }
530         else if (start_position < end_position) {
531             item_width = end_position-start_position;
532         }
533         else{ /* same origin and destination address */
534             end_position = start_position+NODE_CHARS_WIDTH;
535             item_width = NODE_CHARS_WIDTH;
536         }
537
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;
542         }
543
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);
549         }
550
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);
560
561         /* write the frame label */
562
563         g_string_printf(tmp_str, "%s", empty_line->str);
564         overwrite(tmp_str, sai->frame_label,
565             start_position,
566             end_position
567             );
568         fprintf(of, "%s", tmp_str->str);
569
570         /* write the comments */
571         fprintf(of, "%s\n", sai->comment);
572
573         /* write the arrow and frame label*/
574         fprintf(of, "%s", empty_header);
575
576         g_string_printf(tmp_str, "%s", empty_line->str);
577
578         g_string_truncate(tmp_str2, 0);
579
580         if (start_position<end_position) {
581             enlarge_string(tmp_str2, item_width-2, '-');
582             g_string_append_c(tmp_str2, '>');
583         }
584         else{
585             g_string_printf(tmp_str2, "<");
586             enlarge_string(tmp_str2, item_width-1, '-');
587         }
588
589         overwrite(tmp_str, tmp_str2->str,
590             start_position,
591             end_position
592             );
593
594         g_snprintf(src_port, sizeof(src_port), "(%i)", sai->port_src);
595         g_snprintf(dst_port, sizeof(dst_port), "(%i)", sai->port_dst);
596
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);
600         }
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);
604         }
605
606         fprintf(of, "%s\n", tmp_str->str);
607     }
608
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;
618
619 }
620
621 /*
622  * Editor modelines
623  *
624  * Local Variables:
625  * c-basic-offset: 4
626  * tab-width: 8
627  * indent-tabs-mode: nil
628  * End:
629  *
630  * ex: set shiftwidth=4 tabstop=8 expandtab:
631  * :indentSize=4:tabSize=8:noTabs=true:
632  */