3 * Copyright 1998 Mike Hall <mlh@io.com>
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
19 #include <epan/packet.h>
23 struct register_follow
{
24 int proto_id
; /* protocol id (0-indexed) */
25 const char* tap_listen_str
; /* string used in register_tap_listener */
26 follow_conv_filter_func conv_filter
; /* generate "conversation" filter to follow */
27 follow_index_filter_func index_filter
; /* generate stream/index filter to follow */
28 follow_address_filter_func address_filter
; /* generate address filter to follow */
29 follow_port_to_display_func port_to_display
; /* port to name resolution for follow type */
30 tap_packet_cb tap_handler
; /* tap listener handler */
31 follow_stream_count_func stream_count
; /* maximum stream count, used for UI */
32 follow_sub_stream_id_func sub_stream_id
; /* sub-stream id, used for UI */
35 static wmem_tree_t
*registered_followers
;
37 void register_follow_stream(const int proto_id
, const char* tap_listener
,
38 follow_conv_filter_func conv_filter
, follow_index_filter_func index_filter
, follow_address_filter_func address_filter
,
39 follow_port_to_display_func port_to_display
, tap_packet_cb tap_handler
,
40 follow_stream_count_func stream_count
, follow_sub_stream_id_func sub_stream_id
)
42 register_follow_t
*follower
;
43 DISSECTOR_ASSERT(tap_listener
);
44 DISSECTOR_ASSERT(conv_filter
);
45 DISSECTOR_ASSERT(index_filter
);
46 DISSECTOR_ASSERT(address_filter
);
47 DISSECTOR_ASSERT(port_to_display
);
48 DISSECTOR_ASSERT(tap_handler
);
50 follower
= wmem_new(wmem_epan_scope(), register_follow_t
);
52 follower
->proto_id
= proto_id
;
53 follower
->tap_listen_str
= tap_listener
;
54 follower
->conv_filter
= conv_filter
;
55 follower
->index_filter
= index_filter
;
56 follower
->address_filter
= address_filter
;
57 follower
->port_to_display
= port_to_display
;
58 follower
->tap_handler
= tap_handler
;
59 follower
->stream_count
= stream_count
;
60 follower
->sub_stream_id
= sub_stream_id
;
62 if (registered_followers
== NULL
)
63 registered_followers
= wmem_tree_new(wmem_epan_scope());
65 wmem_tree_insert_string(registered_followers
, proto_get_protocol_short_name(find_protocol_by_id(proto_id
)), follower
, 0);
68 int get_follow_proto_id(register_follow_t
* follower
)
73 return follower
->proto_id
;
76 const char* get_follow_tap_string(register_follow_t
* follower
)
81 return follower
->tap_listen_str
;
84 follow_conv_filter_func
get_follow_conv_func(register_follow_t
* follower
)
86 return follower
->conv_filter
;
89 follow_index_filter_func
get_follow_index_func(register_follow_t
* follower
)
91 return follower
->index_filter
;
94 follow_address_filter_func
get_follow_address_func(register_follow_t
* follower
)
96 return follower
->address_filter
;
99 follow_port_to_display_func
get_follow_port_to_display(register_follow_t
* follower
)
101 return follower
->port_to_display
;
104 tap_packet_cb
get_follow_tap_handler(register_follow_t
* follower
)
106 return follower
->tap_handler
;
109 follow_stream_count_func
get_follow_stream_count_func(register_follow_t
* follower
)
111 return follower
->stream_count
;
114 follow_sub_stream_id_func
get_follow_sub_stream_id_func(register_follow_t
* follower
)
116 return follower
->sub_stream_id
;
119 register_follow_t
* get_follow_by_name(const char* proto_short_name
)
121 return (register_follow_t
*)wmem_tree_lookup_string(registered_followers
, proto_short_name
, 0);
124 register_follow_t
* get_follow_by_proto_id(const int proto_id
)
126 protocol_t
*protocol
= find_protocol_by_id(proto_id
);
127 if (protocol
== NULL
) {
131 return (register_follow_t
*)wmem_tree_lookup_string(registered_followers
, proto_get_protocol_short_name(protocol
), 0);
134 void follow_iterate_followers(wmem_foreach_func func
, void *user_data
)
136 wmem_tree_foreach(registered_followers
, func
, user_data
);
139 char* follow_get_stat_tap_string(register_follow_t
* follower
)
141 GString
*cmd_str
= g_string_new("follow,");
142 g_string_append(cmd_str
, proto_get_protocol_filter_name(follower
->proto_id
));
143 return g_string_free(cmd_str
, FALSE
);
146 /* here we are going to try and reconstruct the data portion of a TCP
147 session. We will try and handle duplicates, TCP fragments, and out
148 of order packets in a smart way. */
150 follow_reset_stream(follow_info_t
* info
)
153 follow_record_t
*follow_record
;
155 info
->bytes_written
[0] = info
->bytes_written
[1] = 0;
156 info
->client_port
= 0;
157 info
->server_port
= 0;
159 free_address(&info
->client_ip
);
160 free_address(&info
->server_ip
);
162 for (cur
= info
->payload
; cur
; cur
= g_list_next(cur
)) {
163 follow_record
= (follow_record_t
*)cur
->data
;
164 if(follow_record
->data
)
165 g_byte_array_free(follow_record
->data
, true);
167 g_free(follow_record
);
169 g_list_free(info
->payload
);
170 info
->payload
= NULL
;
172 //Only TCP stream uses fragments
173 for (cur
= info
->fragments
[0]; cur
; cur
= g_list_next(cur
)) {
174 follow_record
= (follow_record_t
*)cur
->data
;
175 if(follow_record
->data
) {
176 g_byte_array_free(follow_record
->data
, true);
178 g_free(follow_record
);
180 for (cur
= info
->fragments
[1]; cur
; cur
= g_list_next(cur
)) {
181 follow_record
= (follow_record_t
*)cur
->data
;
182 if(follow_record
->data
) {
183 g_byte_array_free(follow_record
->data
, true);
185 g_free(follow_record
);
187 info
->fragments
[0] = info
->fragments
[1] = NULL
;
188 info
->seq
[0] = info
->seq
[1] = 0;
190 g_free(info
->filter_out_filter
);
191 info
->filter_out_filter
= NULL
;
193 /* Don't reset the substream_id - that's used by followers for
194 * for determining which tvbs match, and we don't want to clear
195 * it when the taps are reset due to a retap.
198 info
->substream_id
= SUBSTREAM_UNUSED
;
203 follow_info_free(follow_info_t
* follow_info
)
205 follow_reset_stream(follow_info
);
210 follow_tvb_tap_listener(void *tapdata
, packet_info
*pinfo
,
211 epan_dissect_t
*edt _U_
, const void *data
, tap_flags_t flags _U_
)
213 follow_record_t
*follow_record
;
214 follow_info_t
*follow_info
= (follow_info_t
*)tapdata
;
215 tvbuff_t
*next_tvb
= (tvbuff_t
*)data
;
217 follow_record
= g_new(follow_record_t
,1);
219 follow_record
->data
= g_byte_array_sized_new(tvb_captured_length(next_tvb
));
220 follow_record
->data
= g_byte_array_append(follow_record
->data
,
221 tvb_get_ptr(next_tvb
, 0, -1),
222 tvb_captured_length(next_tvb
));
223 follow_record
->packet_num
= pinfo
->fd
->num
;
224 follow_record
->abs_ts
= pinfo
->fd
->abs_ts
;
226 if (follow_info
->client_port
== 0) {
227 follow_info
->client_port
= pinfo
->srcport
;
228 copy_address(&follow_info
->client_ip
, &pinfo
->src
);
229 follow_info
->server_port
= pinfo
->destport
;
230 copy_address(&follow_info
->server_ip
, &pinfo
->dst
);
233 if (addresses_equal(&follow_info
->client_ip
, &pinfo
->src
) && follow_info
->client_port
== pinfo
->srcport
)
234 follow_record
->is_server
= false;
236 follow_record
->is_server
= true;
238 /* update stream counter */
239 follow_info
->bytes_written
[follow_record
->is_server
] += follow_record
->data
->len
;
241 follow_info
->payload
= g_list_prepend(follow_info
->payload
, follow_record
);
242 return TAP_PACKET_DONT_REDRAW
;
246 * Editor modelines - https://www.wireshark.org/tools/modelines.html
251 * indent-tabs-mode: nil
254 * ex: set shiftwidth=2 tabstop=8 expandtab:
255 * :indentSize=2:tabSize=8:noTabs=true: