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
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"
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
)
46 tap_packet_cb
get_conversation_packet_func(register_ct_t
* ct
)
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
;
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
);
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;
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 */
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);
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 */
144 set_conv_gui_data(const void *key _U_
, void *value
, void *userdata
)
146 GString
*conv_cmd_str
= g_string_new("conv,");
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
;
158 ui_info
.params
= NULL
;
159 register_stat_tap_ui(&ui_info
, table
);
160 g_free((char*)ui_info
.cli_string
);
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
);
170 set_endpoint_gui_data(const void *key _U_
, void *value
, void *userdata
)
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
;
182 ui_info
.params
= NULL
;
183 register_stat_tap_ui(&ui_info
, table
);
184 g_free((char*)ui_info
.cli_string
);
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.
216 conversation_hash(const void *v
)
218 const conv_key_t
*key
= (const conv_key_t
*)v
;
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
;
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.
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
)) {
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
)) {
262 * The addresses, ports, or conversation IDs don't match.
268 reset_conversation_table_data(conv_hash_t
*ch
)
274 if (ch
->conv_array
!= NULL
) {
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
);
293 void reset_endpoint_table_data(conv_hash_t
*ch
)
299 if (ch
->conv_array
!= NULL
) {
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
);
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
)
326 return address_to_display(allocator
, addr
);
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
;
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
);
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
;
359 return tcp_port_to_display(allocator
, item
->port
);
361 return udp_port_to_display(allocator
, item
->port
);
363 return sctp_port_to_display(allocator
, item
->port
);
365 return dccp_port_to_display(allocator
, item
->port
);
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.
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
);
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 */
403 ct_port_to_str(conversation_type ctype
, uint32_t port
)
406 case CONVERSATION_TCP
:
407 case CONVERSATION_UDP
:
408 case CONVERSATION_SCTP
:
409 case CONVERSATION_NCP
:
410 return ws_strdup_printf("%d", port
);
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
;
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
)) {
436 new_addr
= wmem_strdup_printf(NULL
, "\"%s\"", src_addr
);
437 wmem_free(NULL
, src_addr
);
440 if (!(conv_item
->ctype
==CONVERSATION_IP
) && (conv_item
->dst_address
.type
== AT_STRINGZ
|| conv_item
->dst_address
.type
== usb_address_type
)) {
443 new_addr
= wmem_strdup_printf(NULL
, "\"%s\"", dst_addr
);
444 wmem_free(NULL
, dst_addr
);
449 case CONV_DIR_A_TO_FROM_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
),
456 sport
?conversation_get_filter_name(conv_item
, CONV_FT_ANY_PORT
):"",
459 conversation_get_filter_name(conv_item
, CONV_FT_DST_ADDRESS
),
462 dport
?conversation_get_filter_name(conv_item
, CONV_FT_ANY_PORT
):"",
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
),
472 sport
?conversation_get_filter_name(conv_item
, CONV_FT_ANY_PORT
):"",
475 conversation_get_filter_name(conv_item
, CONV_FT_ANY_ADDRESS
),
478 dport
?conversation_get_filter_name(conv_item
, CONV_FT_ANY_PORT
):"",
484 case CONV_DIR_A_TO_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
),
490 sport
?conversation_get_filter_name(conv_item
, CONV_FT_SRC_PORT
):"",
493 conversation_get_filter_name(conv_item
, CONV_FT_DST_ADDRESS
),
496 dport
?conversation_get_filter_name(conv_item
, CONV_FT_DST_PORT
):"",
501 case CONV_DIR_A_FROM_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
),
507 sport
?conversation_get_filter_name(conv_item
, CONV_FT_DST_PORT
):"",
510 conversation_get_filter_name(conv_item
, CONV_FT_SRC_ADDRESS
),
513 dport
?conversation_get_filter_name(conv_item
, CONV_FT_SRC_PORT
):"",
518 case CONV_DIR_A_TO_FROM_ANY
:
520 str
= wmem_strdup_printf(NULL
, "%s==%s%s%s%s%s",
521 conversation_get_filter_name(conv_item
, CONV_FT_ANY_ADDRESS
),
524 sport
?conversation_get_filter_name(conv_item
, CONV_FT_ANY_PORT
):"",
529 case CONV_DIR_A_TO_ANY
:
531 str
= wmem_strdup_printf(NULL
, "%s==%s%s%s%s%s",
532 conversation_get_filter_name(conv_item
, CONV_FT_SRC_ADDRESS
),
535 sport
?conversation_get_filter_name(conv_item
, CONV_FT_SRC_PORT
):"",
540 case CONV_DIR_A_FROM_ANY
:
542 str
= wmem_strdup_printf(NULL
, "%s==%s%s%s%s%s",
543 conversation_get_filter_name(conv_item
, CONV_FT_DST_ADDRESS
),
546 sport
?conversation_get_filter_name(conv_item
, CONV_FT_DST_PORT
):"",
551 case CONV_DIR_ANY_TO_FROM_B
:
553 str
= wmem_strdup_printf(NULL
, "%s==%s%s%s%s%s",
554 conversation_get_filter_name(conv_item
, CONV_FT_ANY_ADDRESS
),
557 dport
?conversation_get_filter_name(conv_item
, CONV_FT_ANY_PORT
):"",
562 case CONV_DIR_ANY_FROM_B
:
564 str
= wmem_strdup_printf(NULL
, "%s==%s%s%s%s%s",
565 conversation_get_filter_name(conv_item
, CONV_FT_SRC_ADDRESS
),
568 dport
?conversation_get_filter_name(conv_item
, CONV_FT_SRC_PORT
):"",
573 case CONV_DIR_ANY_TO_B
:
575 str
= wmem_strdup_printf(NULL
, "%s==%s%s%s%s%s",
576 conversation_get_filter_name(conv_item
, CONV_FT_DST_ADDRESS
),
579 dport
?conversation_get_filter_name(conv_item
, CONV_FT_DST_PORT
):"",
585 str
= wmem_strdup(NULL
, "INVALID");
590 wmem_free(NULL
, src_addr
);
591 wmem_free(NULL
, dst_addr
);
595 char *get_endpoint_filter(endpoint_item_t
*endpoint_item
)
597 char *sport
, *src_addr
;
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
){
609 sport
= ws_strdup_printf("%d", endpoint_item
->port
);
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
) {
619 new_addr
= wmem_strdup_printf(NULL
, "\"%s\"", src_addr
);
620 wmem_free(NULL
, src_addr
);
624 str
= ws_strdup_printf("%s==%s%s%s%s%s",
625 endpoint_get_filter_name(endpoint_item
, CONV_FT_ANY_ADDRESS
),
628 sport
?endpoint_get_filter_name(endpoint_item
, CONV_FT_ANY_PORT
):"",
633 wmem_free(NULL
, src_addr
);
637 /* For backwards source and binary compatibility */
638 char *get_hostlist_filter(endpoint_item_t
*endpoint_item
)
640 return get_endpoint_filter(endpoint_item
);
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
);
651 add_conversation_table_data_with_conv_id(
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
));
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
) {
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;
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
));
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;
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
;
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
;
776 conv_item
->rx_frames
+= num_frames
;
777 conv_item
->rx_bytes
+= num_bytes
;
779 conv_item
->filtered
= false;
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
));
795 add_conversation_table_data_extended(
806 ct_dissector_info_t
*ct_info
,
807 conversation_type ctype
,
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
;
825 // invoke the proto callback function which knows how to fill the column(s)
826 ext_tcp
.flows
= proto_conv_cb(ct
);
832 // update conv_item accordingly
833 memcpy(&conv_item
->ext_tcp
, &ext_tcp
, sizeof(conv_item
->ext_tcp
));
837 add_conversation_table_data_ipv4_subnet(
848 ct_dissector_info_t
*ct_info
,
849 conversation_type ctype
)
853 memcpy(&addrSRC
, src
->data
, 4);
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
,
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
897 endpoint_hash(const void *v
)
899 const endpoint_key_t
*key
= (const endpoint_key_t
*)v
;
903 hash_val
= add_address_to_hash(hash_val
, &key
->myaddress
);
904 hash_val
+= key
->port
;
909 * Compare two endpoint keys for an exact match.
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
)) {
922 * The addresses or the ports don't match.
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 */
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
)) {
994 endpoint_item
->tx_frames
+=num_frames
;
995 endpoint_item
->tx_bytes
+=num_bytes
;
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 */
1004 endpoint_item
->tx_frames_total
+=num_frames
;
1005 endpoint_item
->tx_bytes_total
+=num_bytes
;
1007 endpoint_item
->rx_frames_total
+=num_frames
;
1008 endpoint_item
->rx_bytes_total
+=num_bytes
;
1013 add_endpoint_table_data_ipv4_subnet(
1015 const address
*addr
,
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
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
);
1050 add_endpoint_table_data(ch
, addr
, port
, sender
, num_frames
, num_bytes
, et_info
, etype
);
1054 /* For backwards source and binary compatibility */
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
);
1067 * indent-tabs-mode: nil
1070 * ex: set shiftwidth=4 tabstop=8 expandtab:
1071 * :indentSize=4:tabSize=8:noTabs=true: