packet-kerberos: add more PADATA-TYPE values and autogenerate kerberos_PADATA_TYPE_vals
[metze/wireshark/wip.git] / epan / sequence_analysis.c
1 /* sequence-analysis.c
2  * Flow sequence analysis
3  *
4  * Some code from from gtk/flow_graph.c
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12
13 #include "config.h"
14
15 #include "sequence_analysis.h"
16
17 #include "addr_resolv.h"
18 #include "proto.h"
19 #include "color_filters.h"
20 #include "column-info.h"
21 #include "tap.h"
22 #include "wmem/wmem.h"
23
24 #define NODE_OVERFLOW MAX_NUM_NODES+1
25
26 struct register_analysis {
27     const char* name;          /* Name (used for lookup) */
28     const char* ui_name;       /* Name used for UI */
29     int proto_id;              /* protocol id (0-indexed) */
30     const char* tap_listen_str;      /* string used in register_tap_listener (NULL to use protocol name) */
31     guint tap_flags;
32     tap_packet_cb analysis_func;    /* function to be called for new incoming packets for sequence analysis */
33 };
34
35 static wmem_tree_t *registered_seq_analysis = NULL;
36
37 void
38 register_seq_analysis(const char* name, const char* ui_name, const int proto_id, const char* tap_listener, guint tap_flags, tap_packet_cb tap_func)
39 {
40     register_analysis_t* analysis;
41
42     DISSECTOR_ASSERT(tap_func);
43
44     analysis = wmem_new0(wmem_epan_scope(), register_analysis_t);
45
46     analysis->name          = name;
47     analysis->ui_name       = ui_name;
48     analysis->proto_id      = proto_id;
49     if (tap_listener != NULL)
50         analysis->tap_listen_str = tap_listener;
51     else
52         analysis->tap_listen_str = proto_get_protocol_filter_name(proto_id);
53     analysis->tap_flags     = tap_flags;
54     analysis->analysis_func = tap_func;
55
56     if (registered_seq_analysis == NULL)
57         registered_seq_analysis = wmem_tree_new(wmem_epan_scope());
58
59     wmem_tree_insert_string(registered_seq_analysis, name, analysis, 0);
60 }
61
62 const char* sequence_analysis_get_name(register_analysis_t* analysis)
63 {
64     return analysis->name;
65 }
66
67 const char* sequence_analysis_get_ui_name(register_analysis_t* analysis)
68 {
69     return analysis->ui_name;
70 }
71
72 const char* sequence_analysis_get_tap_listener_name(register_analysis_t* analysis)
73 {
74     return analysis->tap_listen_str;
75 }
76
77 tap_packet_cb sequence_analysis_get_packet_func(register_analysis_t* analysis)
78 {
79     return analysis->analysis_func;
80 }
81
82 guint sequence_analysis_get_tap_flags(register_analysis_t* analysis)
83 {
84     return analysis->tap_flags;
85 }
86
87
88 register_analysis_t* sequence_analysis_find_by_name(const char* name)
89 {
90     return (register_analysis_t*)wmem_tree_lookup_string(registered_seq_analysis, name, 0);
91 }
92
93 void sequence_analysis_table_iterate_tables(wmem_foreach_func func, gpointer user_data)
94 {
95     wmem_tree_foreach(registered_seq_analysis, func, user_data);
96 }
97
98 seq_analysis_item_t* sequence_analysis_create_sai_with_addresses(packet_info *pinfo, seq_analysis_info_t *sainfo)
99 {
100     seq_analysis_item_t *sai = NULL;
101     char time_str[COL_MAX_LEN];
102
103     if (sainfo->any_addr) {
104         if (pinfo->net_src.type!=AT_NONE && pinfo->net_dst.type!=AT_NONE) {
105             sai = g_new0(seq_analysis_item_t, 1);
106             copy_address(&(sai->src_addr),&(pinfo->net_src));
107             copy_address(&(sai->dst_addr),&(pinfo->net_dst));
108         }
109
110     } else {
111         if (pinfo->src.type!=AT_NONE && pinfo->dst.type!=AT_NONE) {
112             sai = g_new0(seq_analysis_item_t, 1);
113             copy_address(&(sai->src_addr),&(pinfo->src));
114             copy_address(&(sai->dst_addr),&(pinfo->dst));
115         }
116     }
117
118     if (sai) {
119         /* Fill in the timestamps */
120         set_fd_time(pinfo->epan, pinfo->fd, time_str);
121         sai->time_str = g_strdup(time_str);
122     }
123
124     return sai;
125 }
126
127 void sequence_analysis_use_color_filter(packet_info *pinfo, seq_analysis_item_t *sai)
128 {
129     if (pinfo->fd->color_filter) {
130         sai->bg_color = color_t_to_rgb(&pinfo->fd->color_filter->bg_color);
131         sai->fg_color = color_t_to_rgb(&pinfo->fd->color_filter->fg_color);
132         sai->has_color_filter = TRUE;
133     }
134 }
135
136 void sequence_analysis_use_col_info_as_label_comment(packet_info *pinfo, seq_analysis_item_t *sai)
137 {
138     const gchar *protocol = NULL;
139     const gchar *colinfo = NULL;
140
141     if (pinfo->cinfo) {
142         colinfo = col_get_text(pinfo->cinfo, COL_INFO);
143         protocol = col_get_text(pinfo->cinfo, COL_PROTOCOL);
144     }
145
146     if (colinfo != NULL) {
147         sai->frame_label = g_strdup(colinfo);
148         if (protocol != NULL) {
149             sai->comment = g_strdup_printf("%s: %s", protocol, colinfo);
150         } else {
151             sai->comment = g_strdup(colinfo);
152         }
153     } else {
154         /* This will probably never happen...*/
155         if (protocol != NULL) {
156             sai->frame_label = g_strdup(protocol);
157             sai->comment = g_strdup(protocol);
158         }
159     }
160 }
161
162 seq_analysis_info_t *
163 sequence_analysis_info_new(void)
164 {
165     seq_analysis_info_t *sainfo = g_new0(seq_analysis_info_t, 1);
166
167     /* SEQ_ANALYSIS_DEBUG("adding new item"); */
168     sainfo->items = g_queue_new();
169     sainfo->ht= g_hash_table_new(g_int_hash, g_int_equal);
170     return sainfo;
171 }
172
173 void sequence_analysis_info_free(seq_analysis_info_t *sainfo)
174 {
175     if (!sainfo) return;
176
177     /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */
178     sequence_analysis_list_free(sainfo);
179
180     g_queue_free(sainfo->items);
181     if (sainfo->ht != NULL)
182         g_hash_table_destroy(sainfo->ht);
183
184     g_free(sainfo);
185 }
186
187 static void sequence_analysis_item_free(gpointer data)
188 {
189     seq_analysis_item_t *seq_item = (seq_analysis_item_t *)data;
190     g_free(seq_item->frame_label);
191     g_free(seq_item->time_str);
192     g_free(seq_item->comment);
193     free_address(&seq_item->src_addr);
194     free_address(&seq_item->dst_addr);
195     g_free(data);
196 }
197
198
199 /* compare two list entries by packet no */
200 static gint
201 sequence_analysis_sort_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_)
202 {
203     const seq_analysis_item_t *entry_a = (const seq_analysis_item_t *)a;
204     const seq_analysis_item_t *entry_b = (const seq_analysis_item_t *)b;
205
206     if(entry_a->frame_number < entry_b->frame_number)
207         return -1;
208
209     if(entry_a->frame_number > entry_b->frame_number)
210         return 1;
211
212     return 0;
213 }
214
215
216 void
217 sequence_analysis_list_sort(seq_analysis_info_t *sainfo)
218 {
219     if (!sainfo) return;
220     g_queue_sort(sainfo->items, sequence_analysis_sort_compare, NULL);
221 }
222
223 void
224 sequence_analysis_list_free(seq_analysis_info_t *sainfo)
225 {
226     if (!sainfo) return;
227     /* SEQ_ANALYSIS_DEBUG("%d items", g_queue_get_length(sainfo->items)); */
228
229     /* free the graph data items */
230
231        if (sainfo->items != NULL)
232             g_queue_free_full(sainfo->items, sequence_analysis_item_free);
233        sainfo->items = g_queue_new();
234
235     if (NULL != sainfo->ht) {
236         g_hash_table_remove_all(sainfo->ht);
237     }
238     sainfo->nconv = 0;
239
240     sequence_analysis_free_nodes(sainfo);
241 }
242
243 /* Return the index array if the node is in the array. Return -1 if there is room in the array
244  * and Return -2 if the array is full
245  */
246 /****************************************************************************/
247 static guint add_or_get_node(seq_analysis_info_t *sainfo, address *node) {
248     guint i;
249
250     if (node->type == AT_NONE) return NODE_OVERFLOW;
251
252     for (i=0; i<MAX_NUM_NODES && i < sainfo->num_nodes ; i++) {
253         if ( cmp_address(&(sainfo->nodes[i]), node) == 0 ) return i; /* it is in the array */
254     }
255
256     if (i >= MAX_NUM_NODES) {
257         return  NODE_OVERFLOW;
258     } else {
259         sainfo->num_nodes++;
260         copy_address(&(sainfo->nodes[i]), node);
261         return i;
262     }
263 }
264
265 struct sainfo_counter {
266     seq_analysis_info_t *sainfo;
267     int num_items;
268 };
269
270 static void sequence_analysis_get_nodes_item_proc(gpointer data, gpointer user_data)
271 {
272     seq_analysis_item_t *gai = (seq_analysis_item_t *)data;
273     struct sainfo_counter *sc = (struct sainfo_counter *)user_data;
274     if (gai->display) {
275         (sc->num_items)++;
276         gai->src_node = add_or_get_node(sc->sainfo, &(gai->src_addr));
277         gai->dst_node = add_or_get_node(sc->sainfo, &(gai->dst_addr));
278     }
279 }
280
281 /* Get the nodes from the list */
282 /****************************************************************************/
283 int
284 sequence_analysis_get_nodes(seq_analysis_info_t *sainfo)
285 {
286     struct sainfo_counter sc = {sainfo, 0};
287
288     /* Fill the node array */
289     g_queue_foreach(sainfo->items, sequence_analysis_get_nodes_item_proc, &sc);
290
291     return sc.num_items;
292 }
293
294 /* Free the node address list */
295 /****************************************************************************/
296 void
297 sequence_analysis_free_nodes(seq_analysis_info_t *sainfo)
298 {
299     int i;
300
301     for (i=0; i<MAX_NUM_NODES; i++) {
302         free_address(&sainfo->nodes[i]);
303     }
304     sainfo->num_nodes = 0;
305 }
306
307 /* Writing analysis to file */
308 /****************************************************************************/
309
310 #define NODE_CHARS_WIDTH 20
311 #define CONV_TIME_HEADER       "Conv.| Time    "
312 #define TIME_HEADER "|Time     "
313 #define CONV_TIME_EMPTY_HEADER "     |         "
314 #define TIME_EMPTY_HEADER      "|         "
315 #define CONV_TIME_HEADER_LENGTH 16
316 #define TIME_HEADER_LENGTH 10
317
318 /****************************************************************************/
319 /* Adds trailing characters to complete the requested length.               */
320 /****************************************************************************/
321
322 static void enlarge_string(GString *gstr, guint32 length, char pad) {
323
324     gsize i;
325
326     for (i = gstr->len; i < length; i++) {
327         g_string_append_c(gstr, pad);
328     }
329 }
330
331 /****************************************************************************/
332 /* overwrites the characters in a string, between positions p1 and p2, with */
333 /*   the characters of text_to_insert                                       */
334 /*   NB: it does not check that p1 and p2 fit into string                   */
335 /****************************************************************************/
336
337 static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 p2) {
338
339     glong len, ins_len;
340     gsize pos;
341     gchar *ins_str = NULL;
342
343     if (p1 == p2)
344         return;
345
346     if (p1 > p2) {
347         pos = p2;
348         len = p1 - p2;
349     }
350     else{
351         pos = p1;
352         len = p2 - p1;
353     }
354
355     ins_len = g_utf8_strlen(text_to_insert, -1);
356     if (len > ins_len) {
357         len = ins_len;
358     } else if (len < ins_len) {
359         ins_str = g_utf8_substring(text_to_insert, 0, len);
360     }
361
362     if (!ins_str) ins_str = g_strdup(text_to_insert);
363
364     if (pos > gstr->len)
365         pos = gstr->len;
366
367     g_string_erase(gstr, pos, len);
368
369     g_string_insert(gstr, pos, ins_str);
370     g_free(ins_str);
371 }
372
373
374 void
375 sequence_analysis_dump_to_file(FILE  *of, seq_analysis_info_t *sainfo, unsigned int first_node)
376 {
377     guint32  i, display_items, display_nodes;
378     guint32  start_position, end_position, item_width, header_length;
379     seq_analysis_item_t *sai;
380     guint16  first_conv_num = 0;
381     gboolean several_convs  = FALSE;
382     gboolean first_packet   = TRUE;
383
384     GString    *label_string, *empty_line, *separator_line, *tmp_str, *tmp_str2;
385     const char *empty_header;
386     char        src_port[8], dst_port[8];
387     GList      *list = NULL;
388     char       *addr_str;
389
390     display_items = 0;
391     if (sainfo->items != NULL)
392         list = g_queue_peek_nth_link(sainfo->items, 0);
393
394     while (list)
395     {
396         sai = (seq_analysis_item_t *)list->data;
397         list = g_list_next(list);
398
399         if (!sai->display)
400             continue;
401
402         display_items += 1;
403         if (first_packet) {
404             first_conv_num = sai->conv_num;
405             first_packet = FALSE;
406         }
407         else if (sai->conv_num != first_conv_num) {
408             several_convs = TRUE;
409         }
410     }
411
412     /* if not items to display */
413     if (display_items == 0) {
414         return;
415     }
416
417     label_string   = g_string_new("");
418     empty_line     = g_string_new("");
419     separator_line = g_string_new("");
420     tmp_str        = g_string_new("");
421     tmp_str2       = g_string_new("");
422
423     display_nodes = sainfo->num_nodes;
424
425     /* Write the conv. and time headers */
426     if (several_convs) {
427         fprintf(of, CONV_TIME_HEADER);
428         empty_header = CONV_TIME_EMPTY_HEADER;
429         header_length = CONV_TIME_HEADER_LENGTH;
430     }
431     else{
432         fprintf(of, TIME_HEADER);
433         empty_header = TIME_EMPTY_HEADER;
434         header_length = TIME_HEADER_LENGTH;
435     }
436
437     /* Write the node names on top */
438     for (i=0; i<display_nodes; i+=2) {
439         /* print the node identifiers */
440         addr_str = address_to_display(NULL, &(sainfo->nodes[i+first_node]));
441         g_string_printf(label_string, "| %s", addr_str);
442         wmem_free(NULL, addr_str);
443         enlarge_string(label_string, NODE_CHARS_WIDTH*2, ' ');
444         fprintf(of, "%s", label_string->str);
445         g_string_printf(label_string, "| ");
446         enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
447         g_string_append(empty_line, label_string->str);
448     }
449
450     fprintf(of, "|\n%s", empty_header);
451     g_string_printf(label_string, "| ");
452     enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
453     fprintf(of, "%s", label_string->str);
454
455     /* Write the node names on top */
456     for (i=1; i<display_nodes; i+=2) {
457         /* print the node identifiers */
458         addr_str = address_to_display(NULL, &(sainfo->nodes[i+first_node]));
459         g_string_printf(label_string, "| %s", addr_str);
460         wmem_free(NULL, addr_str);
461         if (label_string->len < NODE_CHARS_WIDTH)
462         {
463             enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
464             g_string_append(label_string, "| ");
465         }
466         enlarge_string(label_string, NODE_CHARS_WIDTH*2, ' ');
467         fprintf(of, "%s", label_string->str);
468         g_string_printf(label_string, "| ");
469         enlarge_string(label_string, NODE_CHARS_WIDTH, ' ');
470         g_string_append(empty_line, label_string->str);
471     }
472
473     fprintf(of, "\n");
474
475     g_string_append_c(empty_line, '|');
476
477     enlarge_string(separator_line, (guint32) empty_line->len + header_length, '-');
478
479     /*
480      * Draw the items
481      */
482
483     list = g_queue_peek_nth_link(sainfo->items, 0);
484     while (list)
485     {
486         sai = (seq_analysis_item_t *)list->data;
487         list = g_list_next(list);
488
489         if (!sai->display)
490             continue;
491
492         start_position = (sai->src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
493
494         end_position = (sai->dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2;
495
496         if (start_position > end_position) {
497             item_width = start_position-end_position;
498         }
499         else if (start_position < end_position) {
500             item_width = end_position-start_position;
501         }
502         else{ /* same origin and destination address */
503             end_position = start_position+NODE_CHARS_WIDTH;
504             item_width = NODE_CHARS_WIDTH;
505         }
506
507         /* separator between conversations */
508         if (sai->conv_num != first_conv_num) {
509             fprintf(of, "%s\n", separator_line->str);
510             first_conv_num = sai->conv_num;
511         }
512
513         /* write the conversation number */
514         if (several_convs) {
515             g_string_printf(label_string, "%i", sai->conv_num);
516             enlarge_string(label_string, 5, ' ');
517             fprintf(of, "%s", label_string->str);
518         }
519
520         if (sai->time_str != NULL) {
521             g_string_printf(label_string, "|%s", sai->time_str);
522             enlarge_string(label_string, 10, ' ');
523             fprintf(of, "%s", label_string->str);
524         }
525
526         /* write the frame label */
527
528         g_string_printf(tmp_str, "%s", empty_line->str);
529         overwrite(tmp_str, sai->frame_label,
530             start_position,
531             end_position
532             );
533         fprintf(of, "%s", tmp_str->str);
534
535         /* write the comments */
536         fprintf(of, "%s\n", sai->comment);
537
538         /* write the arrow and frame label*/
539         fprintf(of, "%s", empty_header);
540
541         g_string_printf(tmp_str, "%s", empty_line->str);
542
543         g_string_truncate(tmp_str2, 0);
544
545         if (start_position<end_position) {
546             enlarge_string(tmp_str2, item_width-2, '-');
547             g_string_append_c(tmp_str2, '>');
548         }
549         else{
550             g_string_printf(tmp_str2, "<");
551             enlarge_string(tmp_str2, item_width-1, '-');
552         }
553
554         overwrite(tmp_str, tmp_str2->str,
555             start_position,
556             end_position
557             );
558
559         g_snprintf(src_port, sizeof(src_port), "(%i)", sai->port_src);
560         g_snprintf(dst_port, sizeof(dst_port), "(%i)", sai->port_dst);
561
562         if (start_position<end_position) {
563             overwrite(tmp_str, src_port, start_position-9, start_position-1);
564             overwrite(tmp_str, dst_port, end_position+1, end_position+9);
565         }
566         else{
567             overwrite(tmp_str, src_port, start_position+1, start_position+9);
568             overwrite(tmp_str, dst_port, end_position-9, end_position+1);
569         }
570
571         fprintf(of, "%s\n", tmp_str->str);
572     }
573
574     g_string_free(label_string, TRUE);
575     g_string_free(empty_line, TRUE);
576     g_string_free(separator_line, TRUE);
577     g_string_free(tmp_str, TRUE);
578     g_string_free(tmp_str2, TRUE);
579 }
580
581 /*
582  * Editor modelines
583  *
584  * Local Variables:
585  * c-basic-offset: 4
586  * tab-width: 8
587  * indent-tabs-mode: nil
588  * End:
589  *
590  * ex: set shiftwidth=4 tabstop=8 expandtab:
591  * :indentSize=4:tabSize=8:noTabs=true:
592  */