dcerpc-netlogon: improve NetrLogonGetCapabilities dissection
[wireshark-sm.git] / epan / conversation_table.c
blob2a50a25a0f3818fb5e199d3e44c3cce907202ad1
1 /* conversations_table.c
2 * conversations_table 2003 Ronnie Sahlberg
3 * Helper routines common to all endpoint conversations tap.
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <string.h>
16 #include "proto.h"
17 #include "packet_info.h"
18 #include "conversation_table.h"
19 #include "addr_resolv.h"
20 #include "address_types.h"
22 #include "stat_tap_ui.h"
24 struct register_ct {
25 bool hide_ports; /* hide TCP / UDP port columns */
26 int proto_id; /* protocol id (0-indexed) */
27 tap_packet_cb conv_func; /* function to be called for new incoming packets for conversations */
28 tap_packet_cb endpoint_func; /* function to be called for new incoming packets for endpoints */
29 conv_gui_init_cb conv_gui_init; /* GUI specific function to initialize conversation */
30 endpoint_gui_init_cb endpoint_gui_init; /* GUI specific function to initialize endpoint */
33 bool get_conversation_hide_ports(register_ct_t* ct)
35 return ct->hide_ports;
38 int get_conversation_proto_id(register_ct_t* ct)
40 if (!ct) {
41 return -1;
43 return ct->proto_id;
46 tap_packet_cb get_conversation_packet_func(register_ct_t* ct)
48 return ct->conv_func;
51 tap_packet_cb get_endpoint_packet_func(register_ct_t* ct)
53 return ct->endpoint_func;
56 /* For backwards source and binary compatibility */
57 tap_packet_cb get_hostlist_packet_func(register_ct_t* ct)
59 return get_endpoint_packet_func(ct);
62 static wmem_tree_t *registered_ct_tables;
64 void
65 dissector_conversation_init(const char *opt_arg, void* userdata)
67 register_ct_t *table = (register_ct_t*)userdata;
68 GString *cmd_str = g_string_new("conv,");
69 const char *filter=NULL;
71 g_string_append(cmd_str, proto_get_protocol_filter_name(table->proto_id));
72 if(!strncmp(opt_arg, cmd_str->str, cmd_str->len)){
73 if (opt_arg[cmd_str->len] == ',') {
74 filter = opt_arg + cmd_str->len + 1;
77 g_string_free(cmd_str, TRUE);
79 if (table->conv_gui_init)
80 table->conv_gui_init(table, filter);
83 void
84 dissector_endpoint_init(const char *opt_arg, void* userdata)
86 register_ct_t *table = (register_ct_t*)userdata;
87 GString *cmd_str = g_string_new("");
88 const char *filter=NULL;
90 g_string_printf(cmd_str, "%s,%s", ENDPOINT_TAP_PREFIX, proto_get_protocol_filter_name(table->proto_id));
91 if(!strncmp(opt_arg, cmd_str->str, cmd_str->len)){
92 if (opt_arg[cmd_str->len] == ',') {
93 filter = opt_arg + cmd_str->len + 1;
95 } else {
96 filter=NULL;
99 g_string_free(cmd_str, TRUE);
101 if (table->endpoint_gui_init)
102 table->endpoint_gui_init(table, filter);
105 /* For backwards source and binary compatibility */
106 void
107 dissector_hostlist_init(const char *opt_arg, void* userdata)
109 dissector_endpoint_init(opt_arg, userdata);
112 /** get conversation from protocol ID
114 * @param proto_id protocol ID
115 * @return tap function handler of conversation
117 register_ct_t* get_conversation_by_proto_id(int proto_id)
119 return (register_ct_t*)wmem_tree_lookup_string(registered_ct_tables, proto_get_protocol_short_name(find_protocol_by_id(proto_id)), 0);
122 void
123 register_conversation_table(const int proto_id, bool hide_ports, tap_packet_cb conv_packet_func, tap_packet_cb endpoint_packet_func)
125 register_ct_t *table;
127 table = wmem_new(wmem_epan_scope(), register_ct_t);
129 table->hide_ports = hide_ports;
130 table->proto_id = proto_id;
131 table->conv_func = conv_packet_func;
132 table->endpoint_func = endpoint_packet_func;
133 table->conv_gui_init = NULL;
134 table->endpoint_gui_init = NULL;
136 if (registered_ct_tables == NULL)
137 registered_ct_tables = wmem_tree_new(wmem_epan_scope());
139 wmem_tree_insert_string(registered_ct_tables, proto_get_protocol_short_name(find_protocol_by_id(proto_id)), table, 0);
142 /* Set GUI fields for register_ct list */
143 static bool
144 set_conv_gui_data(const void *key _U_, void *value, void *userdata)
146 GString *conv_cmd_str = g_string_new("conv,");
147 stat_tap_ui ui_info;
148 register_ct_t *table = (register_ct_t*)value;
150 table->conv_gui_init = (conv_gui_init_cb)userdata;
152 g_string_append(conv_cmd_str, proto_get_protocol_filter_name(table->proto_id));
153 ui_info.group = REGISTER_STAT_GROUP_CONVERSATION_LIST;
154 ui_info.title = NULL; /* construct this from the protocol info? */
155 ui_info.cli_string = g_string_free(conv_cmd_str, FALSE);
156 ui_info.tap_init_cb = dissector_conversation_init;
157 ui_info.nparams = 0;
158 ui_info.params = NULL;
159 register_stat_tap_ui(&ui_info, table);
160 g_free((char*)ui_info.cli_string);
161 return false;
164 void conversation_table_set_gui_info(conv_gui_init_cb init_cb)
166 wmem_tree_foreach(registered_ct_tables, set_conv_gui_data, (void*)init_cb);
169 static bool
170 set_endpoint_gui_data(const void *key _U_, void *value, void *userdata)
172 stat_tap_ui ui_info;
173 register_ct_t *table = (register_ct_t*)value;
175 table->endpoint_gui_init = (endpoint_gui_init_cb)userdata;
177 ui_info.group = REGISTER_STAT_GROUP_ENDPOINT_LIST;
178 ui_info.title = NULL; /* construct this from the protocol info? */
179 ui_info.cli_string = ws_strdup_printf("%s,%s", ENDPOINT_TAP_PREFIX, proto_get_protocol_filter_name(table->proto_id));
180 ui_info.tap_init_cb = dissector_endpoint_init;
181 ui_info.nparams = 0;
182 ui_info.params = NULL;
183 register_stat_tap_ui(&ui_info, table);
184 g_free((char*)ui_info.cli_string);
185 return false;
188 void endpoint_table_set_gui_info(endpoint_gui_init_cb init_cb)
190 wmem_tree_foreach(registered_ct_tables, set_endpoint_gui_data, (void*)init_cb);
193 /* For backwards source and binary compatibility */
194 void hostlist_table_set_gui_info(endpoint_gui_init_cb init_cb)
196 endpoint_table_set_gui_info(init_cb);
199 void conversation_table_iterate_tables(wmem_foreach_func func, void* user_data)
201 wmem_tree_foreach(registered_ct_tables, func, user_data);
204 unsigned conversation_table_get_num(void)
206 return wmem_tree_count(registered_ct_tables);
209 /** Compute the hash value for two given address/port pairs.
210 * (Parameter type is const void *for GHashTable compatibility.)
212 * @param v Conversation Key. MUST point to a conv_key_t struct.
213 * @return Computed key hash.
215 static unsigned
216 conversation_hash(const void *v)
218 const conv_key_t *key = (const conv_key_t *)v;
219 unsigned hash_val;
221 hash_val = 0;
222 hash_val = add_address_to_hash(hash_val, &key->addr1);
223 hash_val += key->port1;
224 hash_val = add_address_to_hash(hash_val, &key->addr2);
225 hash_val += key->port2;
226 hash_val ^= key->conv_id;
228 return hash_val;
231 /** Compare two conversation keys for an exact match.
232 * (Parameter types are const void *for GHashTable compatibility.)
234 * @param key1 First conversation. MUST point to a conv_key_t struct.
235 * @param key2 Second conversation. MUST point to a conv_key_t struct.
236 * @return true if conversations are equal, false otherwise.
238 static gboolean
239 conversation_equal(const void *key1, const void *key2)
241 const conv_key_t *ck1 = (const conv_key_t *)key1;
242 const conv_key_t *ck2 = (const conv_key_t *)key2;
244 if (ck1->conv_id == ck2->conv_id)
246 if (ck1->port1 == ck2->port1 &&
247 ck1->port2 == ck2->port2 &&
248 addresses_equal(&ck1->addr1, &ck2->addr1) &&
249 addresses_equal(&ck1->addr2, &ck2->addr2)) {
250 return TRUE;
253 if (ck1->port2 == ck2->port1 &&
254 ck1->port1 == ck2->port2 &&
255 addresses_equal(&ck1->addr2, &ck2->addr1) &&
256 addresses_equal(&ck1->addr1, &ck2->addr2)) {
257 return TRUE;
262 * The addresses, ports, or conversation IDs don't match.
264 return FALSE;
267 void
268 reset_conversation_table_data(conv_hash_t *ch)
270 if (!ch) {
271 return;
274 if (ch->conv_array != NULL) {
275 unsigned i;
276 for(i = 0; i < ch->conv_array->len; i++){
277 conv_item_t *conv = &g_array_index(ch->conv_array, conv_item_t, i);
278 free_address(&conv->src_address);
279 free_address(&conv->dst_address);
282 g_array_free(ch->conv_array, true);
285 if (ch->hashtable != NULL) {
286 g_hash_table_destroy(ch->hashtable);
289 ch->conv_array=NULL;
290 ch->hashtable=NULL;
293 void reset_endpoint_table_data(conv_hash_t *ch)
295 if (!ch) {
296 return;
299 if (ch->conv_array != NULL) {
300 unsigned i;
301 for(i = 0; i < ch->conv_array->len; i++){
302 endpoint_item_t *endpoint = &g_array_index(ch->conv_array, endpoint_item_t, i);
303 free_address(&endpoint->myaddress);
306 g_array_free(ch->conv_array, true);
309 if (ch->hashtable != NULL) {
310 g_hash_table_destroy(ch->hashtable);
313 ch->conv_array=NULL;
314 ch->hashtable=NULL;
317 /* For backwards source and binary compatibility */
318 void reset_hostlist_table_data(conv_hash_t *ch)
320 reset_endpoint_table_data(ch);
323 char *get_conversation_address(wmem_allocator_t *allocator, address *addr, bool resolve_names)
325 if (resolve_names) {
326 return address_to_display(allocator, addr);
327 } else {
328 return address_to_str(allocator, addr);
332 char *get_conversation_port(wmem_allocator_t *allocator, uint32_t port, conversation_type ctype, bool resolve_names)
335 if(!resolve_names) ctype = CONVERSATION_NONE;
337 switch(ctype) {
338 case(CONVERSATION_TCP):
339 return tcp_port_to_display(allocator, port);
340 case(CONVERSATION_UDP):
341 return udp_port_to_display(allocator, port);
342 case(CONVERSATION_SCTP):
343 return sctp_port_to_display(allocator, port);
344 case(CONVERSATION_DCCP):
345 return dccp_port_to_display(allocator, port);
346 default:
347 return wmem_strdup_printf(allocator, "%d", port);
351 char *get_endpoint_port(wmem_allocator_t *allocator, endpoint_item_t *item, bool resolve_names)
353 endpoint_type etype = item->etype;
355 if(!resolve_names) etype = ENDPOINT_NONE;
357 switch(etype) {
358 case(ENDPOINT_TCP):
359 return tcp_port_to_display(allocator, item->port);
360 case(ENDPOINT_UDP):
361 return udp_port_to_display(allocator, item->port);
362 case(ENDPOINT_SCTP):
363 return sctp_port_to_display(allocator, item->port);
364 case(ENDPOINT_DCCP):
365 return dccp_port_to_display(allocator, item->port);
366 default:
367 return wmem_strdup_printf(allocator, "%d", item->port);
371 /* given an address (to distinguish between ipv4 and ipv6 for tcp/udp),
372 a endpoint_type and a name_type (FN_...)
373 return a string for the filter name.
375 Some addresses, like AT_ETHER may actually be any of multiple types
376 of protocols, either ethernet, tokenring, fddi, wlan etc so we must be
377 more specific there; that's why we need specific_addr_type.
379 static const char *
380 conversation_get_filter_name(conv_item_t *conv_item, conv_filter_type_e filter_type)
383 if ((conv_item == NULL) || (conv_item->dissector_info == NULL) || (conv_item->dissector_info->get_filter_type == NULL)) {
384 return CONV_FILTER_INVALID;
387 return conv_item->dissector_info->get_filter_type(conv_item, filter_type);
390 static const char *
391 endpoint_get_filter_name(endpoint_item_t *endpoint, conv_filter_type_e filter_type)
394 if ((endpoint == NULL) || (endpoint->dissector_info == NULL) || (endpoint->dissector_info->get_filter_type == NULL)) {
395 return CONV_FILTER_INVALID;
398 return endpoint->dissector_info->get_filter_type(endpoint, filter_type);
401 /* Convert a port number into a string or NULL */
402 static char *
403 ct_port_to_str(conversation_type ctype, uint32_t port)
405 switch(ctype){
406 case CONVERSATION_TCP:
407 case CONVERSATION_UDP:
408 case CONVERSATION_SCTP:
409 case CONVERSATION_NCP:
410 return ws_strdup_printf("%d", port);
411 default:
412 break;
414 return NULL;
417 static int usb_address_type = -1;
419 char *get_conversation_filter(conv_item_t *conv_item, conv_direction_e direction)
421 char *sport, *dport, *src_addr, *dst_addr;
422 char *str;
424 /* XXX - Hack until we find something better */
425 if (usb_address_type == -1)
426 usb_address_type = address_type_get_by_name("AT_USB");
428 sport = ct_port_to_str(conv_item->ctype, conv_item->src_port);
429 dport = ct_port_to_str(conv_item->ctype, conv_item->dst_port);
430 src_addr = address_to_str(NULL, &conv_item->src_address);
431 dst_addr = address_to_str(NULL, &conv_item->dst_address);
433 if (!(conv_item->ctype==CONVERSATION_IP) && (conv_item->src_address.type == AT_STRINGZ || conv_item->src_address.type == usb_address_type)) {
434 char *new_addr;
436 new_addr = wmem_strdup_printf(NULL, "\"%s\"", src_addr);
437 wmem_free(NULL, src_addr);
438 src_addr = new_addr;
440 if (!(conv_item->ctype==CONVERSATION_IP) && (conv_item->dst_address.type == AT_STRINGZ || conv_item->dst_address.type == usb_address_type)) {
441 char *new_addr;
443 new_addr = wmem_strdup_printf(NULL, "\"%s\"", dst_addr);
444 wmem_free(NULL, dst_addr);
445 dst_addr = new_addr;
448 switch(direction){
449 case CONV_DIR_A_TO_FROM_B:
450 /* A <-> B */
451 if(strcmp(src_addr, dst_addr)==0) {
452 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s && %s==%s%s%s%s%s",
453 conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS),
454 src_addr,
455 sport?" && ":"",
456 sport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"",
457 sport?"==":"",
458 sport?sport:"",
459 conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS),
460 dst_addr,
461 dport?" && ":"",
462 dport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"",
463 dport?"==":"",
464 dport?dport:""
467 else {
468 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s && %s==%s%s%s%s%s",
469 conversation_get_filter_name(conv_item, CONV_FT_ANY_ADDRESS),
470 src_addr,
471 sport?" && ":"",
472 sport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"",
473 sport?"==":"",
474 sport?sport:"",
475 conversation_get_filter_name(conv_item, CONV_FT_ANY_ADDRESS),
476 dst_addr,
477 dport?" && ":"",
478 dport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"",
479 dport?"==":"",
480 dport?dport:""
483 break;
484 case CONV_DIR_A_TO_B:
485 /* A --> B */
486 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s && %s==%s%s%s%s%s",
487 conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS),
488 src_addr,
489 sport?" && ":"",
490 sport?conversation_get_filter_name(conv_item, CONV_FT_SRC_PORT):"",
491 sport?"==":"",
492 sport?sport:"",
493 conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS),
494 dst_addr,
495 dport?" && ":"",
496 dport?conversation_get_filter_name(conv_item, CONV_FT_DST_PORT):"",
497 dport?"==":"",
498 dport?dport:""
500 break;
501 case CONV_DIR_A_FROM_B:
502 /* A <-- B */
503 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s && %s==%s%s%s%s%s",
504 conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS),
505 src_addr,
506 sport?" && ":"",
507 sport?conversation_get_filter_name(conv_item, CONV_FT_DST_PORT):"",
508 sport?"==":"",
509 sport?sport:"",
510 conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS),
511 dst_addr,
512 dport?" && ":"",
513 dport?conversation_get_filter_name(conv_item, CONV_FT_SRC_PORT):"",
514 dport?"==":"",
515 dport?dport:""
517 break;
518 case CONV_DIR_A_TO_FROM_ANY:
519 /* A <-> ANY */
520 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s",
521 conversation_get_filter_name(conv_item, CONV_FT_ANY_ADDRESS),
522 src_addr,
523 sport?" && ":"",
524 sport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"",
525 sport?"==":"",
526 sport?sport:""
528 break;
529 case CONV_DIR_A_TO_ANY:
530 /* A --> ANY */
531 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s",
532 conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS),
533 src_addr,
534 sport?" && ":"",
535 sport?conversation_get_filter_name(conv_item, CONV_FT_SRC_PORT):"",
536 sport?"==":"",
537 sport?sport:""
539 break;
540 case CONV_DIR_A_FROM_ANY:
541 /* A <-- ANY */
542 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s",
543 conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS),
544 src_addr,
545 sport?" && ":"",
546 sport?conversation_get_filter_name(conv_item, CONV_FT_DST_PORT):"",
547 sport?"==":"",
548 sport?sport:""
550 break;
551 case CONV_DIR_ANY_TO_FROM_B:
552 /* ANY <-> B */
553 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s",
554 conversation_get_filter_name(conv_item, CONV_FT_ANY_ADDRESS),
555 dst_addr,
556 dport?" && ":"",
557 dport?conversation_get_filter_name(conv_item, CONV_FT_ANY_PORT):"",
558 dport?"==":"",
559 dport?dport:""
561 break;
562 case CONV_DIR_ANY_FROM_B:
563 /* ANY <-- B */
564 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s",
565 conversation_get_filter_name(conv_item, CONV_FT_SRC_ADDRESS),
566 dst_addr,
567 dport?" && ":"",
568 dport?conversation_get_filter_name(conv_item, CONV_FT_SRC_PORT):"",
569 dport?"==":"",
570 dport?dport:""
572 break;
573 case CONV_DIR_ANY_TO_B:
574 /* ANY --> B */
575 str = wmem_strdup_printf(NULL, "%s==%s%s%s%s%s",
576 conversation_get_filter_name(conv_item, CONV_FT_DST_ADDRESS),
577 dst_addr,
578 dport?" && ":"",
579 dport?conversation_get_filter_name(conv_item, CONV_FT_DST_PORT):"",
580 dport?"==":"",
581 dport?dport:""
583 break;
584 default:
585 str = wmem_strdup(NULL, "INVALID");
586 break;
588 g_free(sport);
589 g_free(dport);
590 wmem_free(NULL, src_addr);
591 wmem_free(NULL, dst_addr);
592 return str;
595 char *get_endpoint_filter(endpoint_item_t *endpoint_item)
597 char *sport, *src_addr;
598 char *str;
600 /* XXX - Hack until we find something better */
601 if (usb_address_type == -1)
602 usb_address_type = address_type_get_by_name("AT_USB");
604 switch(endpoint_item->etype){
605 case ENDPOINT_TCP:
606 case ENDPOINT_UDP:
607 case ENDPOINT_SCTP:
608 case ENDPOINT_NCP:
609 sport = ws_strdup_printf("%d", endpoint_item->port);
610 break;
611 default:
612 sport = NULL;
613 break;
615 src_addr = address_to_str(NULL, &endpoint_item->myaddress);
616 if (endpoint_item->myaddress.type == AT_STRINGZ || endpoint_item->myaddress.type == usb_address_type) {
617 char *new_addr;
619 new_addr = wmem_strdup_printf(NULL, "\"%s\"", src_addr);
620 wmem_free(NULL, src_addr);
621 src_addr = new_addr;
624 str = ws_strdup_printf("%s==%s%s%s%s%s",
625 endpoint_get_filter_name(endpoint_item, CONV_FT_ANY_ADDRESS),
626 src_addr,
627 sport?" && ":"",
628 sport?endpoint_get_filter_name(endpoint_item, CONV_FT_ANY_PORT):"",
629 sport?"==":"",
630 sport?sport:"");
632 g_free(sport);
633 wmem_free(NULL, src_addr);
634 return str;
637 /* For backwards source and binary compatibility */
638 char *get_hostlist_filter(endpoint_item_t *endpoint_item)
640 return get_endpoint_filter(endpoint_item);
643 void
644 add_conversation_table_data(conv_hash_t *ch, const address *src, const address *dst, uint32_t src_port, uint32_t dst_port, int num_frames, int num_bytes,
645 nstime_t *ts, nstime_t *abs_ts, ct_dissector_info_t *ct_info, conversation_type ctype)
647 add_conversation_table_data_with_conv_id(ch, src, dst, src_port, dst_port, CONV_ID_UNSET, num_frames, num_bytes, ts, abs_ts, ct_info, ctype);
650 conv_item_t *
651 add_conversation_table_data_with_conv_id(
652 conv_hash_t *ch,
653 const address *src,
654 const address *dst,
655 uint32_t src_port,
656 uint32_t dst_port,
657 conv_id_t conv_id,
658 int num_frames,
659 int num_bytes,
660 nstime_t *ts,
661 nstime_t *abs_ts,
662 ct_dissector_info_t *ct_info,
663 conversation_type ctype)
665 conv_item_t *conv_item = NULL;
666 bool is_fwd_direction = false; /* direction of any conversation found */
668 /* if we don't have any entries at all yet */
669 if (ch->conv_array == NULL) {
670 ch->conv_array = g_array_sized_new(false, false, sizeof(conv_item_t), 10000);
672 ch->hashtable = g_hash_table_new_full(conversation_hash,
673 conversation_equal, /* key_equal_func */
674 g_free, /* key_destroy_func */
675 NULL); /* value_destroy_func */
677 } else { /* try to find it among the existing known conversations */
678 /* first, check in the fwd conversations */
679 conv_key_t existing_key;
680 void *conversation_idx_hash_val;
682 existing_key.addr1 = *src;
683 existing_key.addr2 = *dst;
684 existing_key.port1 = src_port;
685 existing_key.port2 = dst_port;
686 existing_key.conv_id = conv_id;
687 if (g_hash_table_lookup_extended(ch->hashtable, &existing_key, NULL, &conversation_idx_hash_val)) {
688 conv_item = &g_array_index(ch->conv_array, conv_item_t, GPOINTER_TO_UINT(conversation_idx_hash_val));
690 if (conv_item == NULL) {
691 /* then, check in the rev conversations if not found in 'fwd' */
692 existing_key.addr1 = *dst;
693 existing_key.addr2 = *src;
694 existing_key.port1 = dst_port;
695 existing_key.port2 = src_port;
696 if (g_hash_table_lookup_extended(ch->hashtable, &existing_key, NULL, &conversation_idx_hash_val)) {
697 conv_item = &g_array_index(ch->conv_array, conv_item_t, GPOINTER_TO_UINT(conversation_idx_hash_val));
699 } else {
700 /* a conversation was found in this same fwd direction */
701 is_fwd_direction = true;
705 /* if we still don't know what conversation this is it has to be a new one
706 and we have to allocate it and append it to the end of the list */
707 if (conv_item == NULL) {
708 conv_key_t *new_key;
709 conv_item_t new_conv_item;
710 unsigned int conversation_idx;
712 copy_address(&new_conv_item.src_address, src);
713 copy_address(&new_conv_item.dst_address, dst);
714 new_conv_item.dissector_info = ct_info;
715 new_conv_item.ctype = ctype;
716 new_conv_item.src_port = src_port;
717 new_conv_item.dst_port = dst_port;
718 new_conv_item.conv_id = conv_id;
719 new_conv_item.rx_frames = 0;
720 new_conv_item.tx_frames = 0;
721 new_conv_item.rx_bytes = 0;
722 new_conv_item.tx_bytes = 0;
723 new_conv_item.rx_frames_total = 0;
724 new_conv_item.tx_frames_total = 0;
725 new_conv_item.rx_bytes_total = 0;
726 new_conv_item.tx_bytes_total = 0;
728 if (ts) {
729 memcpy(&new_conv_item.start_time, ts, sizeof(new_conv_item.start_time));
730 memcpy(&new_conv_item.stop_time, ts, sizeof(new_conv_item.stop_time));
731 memcpy(&new_conv_item.start_abs_time, abs_ts, sizeof(new_conv_item.start_abs_time));
732 } else {
733 nstime_set_unset(&new_conv_item.start_abs_time);
734 nstime_set_unset(&new_conv_item.start_time);
735 nstime_set_unset(&new_conv_item.stop_time);
737 g_array_append_val(ch->conv_array, new_conv_item);
738 conversation_idx = ch->conv_array->len - 1;
739 conv_item = &g_array_index(ch->conv_array, conv_item_t, conversation_idx);
741 /* ct->conversations address is not a constant but src/dst_address.data are */
742 new_key = g_new(conv_key_t, 1);
743 set_address(&new_key->addr1, conv_item->src_address.type, conv_item->src_address.len, conv_item->src_address.data);
744 set_address(&new_key->addr2, conv_item->dst_address.type, conv_item->dst_address.len, conv_item->dst_address.data);
745 new_key->port1 = src_port;
746 new_key->port2 = dst_port;
747 new_key->conv_id = conv_id;
748 g_hash_table_insert(ch->hashtable, new_key, GUINT_TO_POINTER(conversation_idx));
750 /* update the conversation struct */
751 conv_item->tx_frames_total += num_frames;
752 conv_item->tx_bytes_total += num_bytes;
753 conv_item->filtered = true;
754 if (! (ch->flags & TL_DISPLAY_FILTER_IGNORED)) {
755 conv_item->tx_frames += num_frames;
756 conv_item->tx_bytes += num_bytes;
757 conv_item->filtered = false;
759 } else {
761 * update an existing conversation
762 * update the conversation struct
764 if (is_fwd_direction) {
765 conv_item->tx_frames_total += num_frames;
766 conv_item->tx_bytes_total += num_bytes;
767 } else {
768 conv_item->rx_frames_total += num_frames;
769 conv_item->rx_bytes_total += num_bytes;
771 if (! (ch->flags & TL_DISPLAY_FILTER_IGNORED)) {
772 if( is_fwd_direction ){
773 conv_item->tx_frames += num_frames;
774 conv_item->tx_bytes += num_bytes;
775 } else {
776 conv_item->rx_frames += num_frames;
777 conv_item->rx_bytes += num_bytes;
779 conv_item->filtered = false;
783 if (ts) {
784 if (nstime_cmp(ts, &conv_item->stop_time) > 0) {
785 memcpy(&conv_item->stop_time, ts, sizeof(conv_item->stop_time));
786 } else if (nstime_cmp(ts, &conv_item->start_time) < 0) {
787 memcpy(&conv_item->start_time, ts, sizeof(conv_item->start_time));
788 memcpy(&conv_item->start_abs_time, abs_ts, sizeof(conv_item->start_abs_time));
791 return conv_item;
794 void
795 add_conversation_table_data_extended(
796 conv_hash_t *ch,
797 const address *src,
798 const address *dst,
799 uint32_t src_port,
800 uint32_t dst_port,
801 conv_id_t conv_id,
802 int num_frames,
803 int num_bytes,
804 nstime_t *ts,
805 nstime_t *abs_ts,
806 ct_dissector_info_t *ct_info,
807 conversation_type ctype,
808 uint32_t frameid,
809 int (*proto_conv_cb)(conversation_t *) )
811 /* delegate the conversation_table update to the decorated function */
812 conv_item_t *conv_item = add_conversation_table_data_with_conv_id(ch, src, dst, src_port, dst_port, conv_id, num_frames, num_bytes, ts, abs_ts, ct_info, ctype);
815 * Relies heavily on frameid to identify the conversation.
816 * XXX - Later on, either implement one more find_conversation() function to look for
817 * conv_id in the 'addr/port tuple' Htable, or move the conversation to the convid Htable to
818 * build a quickier identification method.
820 conversation_t *ct = find_conversation(frameid, src, dst, ctype, src_port, dst_port, 0);
822 conv_extension_tcp_t ext_tcp;
824 if(ct != NULL) {
825 // invoke the proto callback function which knows how to fill the column(s)
826 ext_tcp.flows = proto_conv_cb(ct);
828 else {
829 ext_tcp.flows = 0;
832 // update conv_item accordingly
833 memcpy(&conv_item->ext_tcp, &ext_tcp, sizeof(conv_item->ext_tcp));
836 void
837 add_conversation_table_data_ipv4_subnet(
838 conv_hash_t *ch,
839 const address *src,
840 const address *dst,
841 uint32_t src_port,
842 uint32_t dst_port,
843 conv_id_t conv_id,
844 int num_frames,
845 int num_bytes,
846 nstime_t *ts,
847 nstime_t *abs_ts,
848 ct_dissector_info_t *ct_info,
849 conversation_type ctype)
852 unsigned addrSRC;
853 memcpy(&addrSRC, src->data, 4);
854 unsigned addrDST;
855 memcpy(&addrDST, dst->data, 4);
857 bool is_src_aggregated = false;
858 bool is_dst_aggregated = false;
860 hashipv4_t * volatile tpsrc;
861 tpsrc = new_ipv4(addrSRC);
862 is_src_aggregated = fill_dummy_ip4(addrSRC, tpsrc);
864 hashipv4_t * volatile tpdst;
865 tpdst = new_ipv4(addrDST);
866 is_dst_aggregated = fill_dummy_ip4(addrDST, tpdst);
868 address *aggsrc = NULL;
869 aggsrc = wmem_new(wmem_epan_scope(), address);
871 aggsrc->len = (int)strlen(tpsrc->cidr_addr);
872 aggsrc->data = wmem_strdup(wmem_file_scope(), tpsrc->cidr_addr);
873 aggsrc->type = AT_STRINGZ;
875 address *aggdst = NULL;
876 aggdst = wmem_new(wmem_epan_scope(), address);
877 aggdst->len = (int)strlen(tpdst->cidr_addr);
878 aggdst->data = wmem_strdup(wmem_file_scope(), tpdst->cidr_addr);
879 aggdst->type = AT_STRINGZ;
881 /* add data with subnets if we have any, or actual src & dst
882 * unset the conv_id when dealing with subnets
884 add_conversation_table_data_with_conv_id(ch,
885 is_src_aggregated?aggsrc:src,
886 is_dst_aggregated?aggdst:dst,
887 src_port, dst_port,
888 (is_src_aggregated||is_dst_aggregated?CONV_ID_UNSET:conv_id),
889 num_frames, num_bytes, ts, abs_ts, ct_info, ctype);
893 * Compute the hash value for a given address/port pair if the match
894 * is to be exact.
896 static unsigned
897 endpoint_hash(const void *v)
899 const endpoint_key_t *key = (const endpoint_key_t *)v;
900 unsigned hash_val;
902 hash_val = 0;
903 hash_val = add_address_to_hash(hash_val, &key->myaddress);
904 hash_val += key->port;
905 return hash_val;
909 * Compare two endpoint keys for an exact match.
911 static int
912 endpoint_match(const void *v, const void *w)
914 const endpoint_key_t *v1 = (const endpoint_key_t *)v;
915 const endpoint_key_t *v2 = (const endpoint_key_t *)w;
917 if (v1->port == v2->port &&
918 addresses_equal(&v1->myaddress, &v2->myaddress)) {
919 return 1;
922 * The addresses or the ports don't match.
924 return 0;
927 void
928 add_endpoint_table_data(conv_hash_t *ch, const address *addr, uint32_t port, bool sender, int num_frames, int num_bytes, et_dissector_info_t *et_info, endpoint_type etype)
930 endpoint_item_t *endpoint_item = NULL;
932 /* XXX should be optimized to allocate n extra entries at a time
933 instead of just one */
934 /* if we don't have any entries at all yet */
935 if(ch->conv_array==NULL){
936 ch->conv_array=g_array_sized_new(false, false, sizeof(endpoint_item_t), 10000);
937 ch->hashtable = g_hash_table_new_full(endpoint_hash,
938 endpoint_match, /* key_equal_func */
939 g_free, /* key_destroy_func */
940 NULL); /* value_destroy_func */
942 else {
943 /* try to find it among the existing known conversations */
944 endpoint_key_t existing_key;
945 void *endpoint_idx_hash_val;
947 copy_address_shallow(&existing_key.myaddress, addr);
948 existing_key.port = port;
950 if (g_hash_table_lookup_extended(ch->hashtable, &existing_key, NULL, &endpoint_idx_hash_val)) {
951 endpoint_item = &g_array_index(ch->conv_array, endpoint_item_t, GPOINTER_TO_UINT(endpoint_idx_hash_val));
955 /* if we still don't know what endpoint this is it has to be a new one
956 and we have to allocate it and append it to the end of the list */
957 if(endpoint_item==NULL){
958 endpoint_key_t *new_key;
959 endpoint_item_t new_endpoint_item;
960 unsigned int endpoint_idx;
962 copy_address(&new_endpoint_item.myaddress, addr);
963 new_endpoint_item.dissector_info = et_info;
964 new_endpoint_item.etype=etype;
965 new_endpoint_item.port=port;
966 new_endpoint_item.rx_frames=0;
967 new_endpoint_item.tx_frames=0;
968 new_endpoint_item.rx_bytes=0;
969 new_endpoint_item.tx_bytes=0;
970 new_endpoint_item.rx_frames_total=0;
971 new_endpoint_item.tx_frames_total=0;
972 new_endpoint_item.rx_bytes_total=0;
973 new_endpoint_item.tx_bytes_total=0;
974 new_endpoint_item.modified = true;
975 new_endpoint_item.filtered = true;
977 g_array_append_val(ch->conv_array, new_endpoint_item);
978 endpoint_idx = ch->conv_array->len - 1;
979 endpoint_item = &g_array_index(ch->conv_array, endpoint_item_t, endpoint_idx);
981 /* hl->hosts address is not a constant but address.data is */
982 new_key = g_new(endpoint_key_t,1);
983 set_address(&new_key->myaddress, endpoint_item->myaddress.type, endpoint_item->myaddress.len, endpoint_item->myaddress.data);
984 new_key->port = port;
985 g_hash_table_insert(ch->hashtable, new_key, GUINT_TO_POINTER(endpoint_idx));
988 /* if this is a new endpoint we need to initialize the struct */
989 endpoint_item->modified = true;
991 /* update the endpoint struct */
992 if (! (ch->flags & TL_DISPLAY_FILTER_IGNORED)) {
993 if( sender ){
994 endpoint_item->tx_frames+=num_frames;
995 endpoint_item->tx_bytes+=num_bytes;
996 } else {
997 endpoint_item->rx_frames+=num_frames;
998 endpoint_item->rx_bytes+=num_bytes;
1000 endpoint_item->filtered = false;
1002 /* update the endpoint struct for total values */
1003 if( sender ){
1004 endpoint_item->tx_frames_total+=num_frames;
1005 endpoint_item->tx_bytes_total+=num_bytes;
1006 } else {
1007 endpoint_item->rx_frames_total+=num_frames;
1008 endpoint_item->rx_bytes_total+=num_bytes;
1012 void
1013 add_endpoint_table_data_ipv4_subnet(
1014 conv_hash_t *ch,
1015 const address *addr,
1016 uint32_t port,
1017 bool sender,
1018 int num_frames,
1019 int num_bytes,
1020 et_dissector_info_t *et_info,
1021 endpoint_type etype)
1023 unsigned addrSubnetted;
1024 memcpy(&addrSubnetted, addr->data, 4);
1026 bool is_aggregated = false;
1028 hashipv4_t * volatile tpaddr;
1029 tpaddr = new_ipv4(addrSubnetted);
1030 is_aggregated = fill_dummy_ip4(addrSubnetted, tpaddr);
1032 address *aggaddr = NULL;
1033 aggaddr = wmem_new(wmem_epan_scope(), address);
1035 aggaddr->len = (int)strlen(tpaddr->cidr_addr);
1036 aggaddr->data = wmem_strdup(wmem_file_scope(), tpaddr->cidr_addr);
1037 aggaddr->type = AT_STRINGZ;
1039 /* add data with subnets if we have any, or actual addr
1041 if(is_aggregated) {
1042 add_endpoint_table_data(ch, aggaddr, port, sender, num_frames, num_bytes, et_info, etype);
1044 // besides, add the original non-aggregated data when asked to
1045 if(ch->flags & TL_IP_AGGREGATION_ORI) {
1046 add_endpoint_table_data(ch, addr, port, sender, num_frames, num_bytes, et_info, etype);
1049 else {
1050 add_endpoint_table_data(ch, addr, port, sender, num_frames, num_bytes, et_info, etype);
1054 /* For backwards source and binary compatibility */
1055 void
1056 add_hostlist_table_data(conv_hash_t *ch, const address *addr, uint32_t port, bool sender, int num_frames, int num_bytes, et_dissector_info_t *et_info, endpoint_type etype)
1058 add_endpoint_table_data(ch, addr, port, sender, num_frames, num_bytes, et_info, etype);
1062 * Editor modelines
1064 * Local Variables:
1065 * c-basic-offset: 4
1066 * tab-width: 8
1067 * indent-tabs-mode: nil
1068 * End:
1070 * ex: set shiftwidth=4 tabstop=8 expandtab:
1071 * :indentSize=4:tabSize=8:noTabs=true: