1 /* follow.c
2  *
3  * Copyright 1998 Mike Hall <mlh@io.com>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  *
11  */
12 
13 #include "config.h"
14 
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include <glib.h>
19 #include <epan/packet.h>
20 #include "follow.h"
21 #include <epan/tap.h>
22 
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 };
32 
33 static wmem_tree_t *registered_followers = NULL;
34 
35 void register_follow_stream(const int proto_id, const char* tap_listener,
36                             follow_conv_filter_func conv_filter, follow_index_filter_func index_filter, follow_address_filter_func address_filter,
37                             follow_port_to_display_func port_to_display, tap_packet_cb tap_handler)
38 {
signal_handler(Handler & h)39   register_follow_t *follower;
40   DISSECTOR_ASSERT(tap_listener);
41   DISSECTOR_ASSERT(conv_filter);
42   DISSECTOR_ASSERT(index_filter);
43   DISSECTOR_ASSERT(address_filter);
44   DISSECTOR_ASSERT(port_to_display);
45   DISSECTOR_ASSERT(tap_handler);
do_complete(void * owner,operation * base,const boost::system::error_code &,std::size_t)46 
47   follower = wmem_new(wmem_epan_scope(), register_follow_t);
48 
49   follower->proto_id       = proto_id;
50   follower->tap_listen_str = tap_listener;
51   follower->conv_filter    = conv_filter;
52   follower->index_filter   = index_filter;
53   follower->address_filter = address_filter;
54   follower->port_to_display = port_to_display;
55   follower->tap_handler    = tap_handler;
56 
57   if (registered_followers == NULL)
58     registered_followers = wmem_tree_new(wmem_epan_scope());
59 
60   wmem_tree_insert_string(registered_followers, proto_get_protocol_short_name(find_protocol_by_id(proto_id)), follower, 0);
61 }
62 
63 int get_follow_proto_id(register_follow_t* follower)
64 {
65   if (follower == NULL)
66     return -1;
67 
68   return follower->proto_id;
69 }
70 
71 const char* get_follow_tap_string(register_follow_t* follower)
72 {
73   if (follower == NULL)
74     return "";
75 
76   return follower->tap_listen_str;
77 }
78 
79 follow_conv_filter_func get_follow_conv_func(register_follow_t* follower)
80 {
81   return follower->conv_filter;
82 }
83 
84 follow_index_filter_func get_follow_index_func(register_follow_t* follower)
85 {
86   return follower->index_filter;
87 }
88 
89 follow_address_filter_func get_follow_address_func(register_follow_t* follower)
90 {
91   return follower->address_filter;
92 }
93 
94 follow_port_to_display_func get_follow_port_to_display(register_follow_t* follower)
95 {
96   return follower->port_to_display;
97 }
98 
99 tap_packet_cb get_follow_tap_handler(register_follow_t* follower)
100 {
101   return follower->tap_handler;
102 }
103 
104 
105 register_follow_t* get_follow_by_name(const char* proto_short_name)
106 {
107   return (register_follow_t*)wmem_tree_lookup_string(registered_followers, proto_short_name, 0);
108 }
109 
110 void follow_iterate_followers(wmem_foreach_func func, gpointer user_data)
111 {
112     wmem_tree_foreach(registered_followers, func, user_data);
113 }
114 
115 gchar* follow_get_stat_tap_string(register_follow_t* follower)
116 {
117     GString *cmd_str = g_string_new("follow,");
118     g_string_append(cmd_str, proto_get_protocol_filter_name(follower->proto_id));
119     return g_string_free(cmd_str, FALSE);
120 }
121 
122 /* here we are going to try and reconstruct the data portion of a TCP
123    session. We will try and handle duplicates, TCP fragments, and out
124    of order packets in a smart way. */
125 void
126 follow_reset_stream(follow_info_t* info)
127 {
128     info->bytes_written[0] = info->bytes_written[1] = 0;
129     info->client_port = 0;
130     info->server_port = 0;
131     info->client_ip.type = FT_NONE;
132     info->client_ip.len = 0;
133     info->server_ip.type = FT_NONE;
134     info->server_ip.len = 0;
135     info->fragments[0] = info->fragments[1] = NULL;
136     info->seq[0] = info->seq[1] = 0;
137     info->substream_id = SUBSTREAM_UNUSED;
138 }
139 
140 void
141 follow_info_free(follow_info_t* follow_info)
142 {
143     GList *cur;
144     follow_record_t *follow_record;
145 
146     for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
147         if(cur->data) {
148             follow_record = (follow_record_t *)cur->data;
149             if(follow_record->data)
150                 g_byte_array_free(follow_record->data, TRUE);
151 
152             g_free(follow_record);
153         }
154     }
155     g_list_free(follow_info->payload);
156 
157     //Only TCP stream uses fragments
158     for (cur = follow_info->fragments[0]; cur; cur = g_list_next(cur)) {
159         follow_record = (follow_record_t *)cur->data;
160         if(follow_record->data) {
161             g_byte_array_free(follow_record->data, TRUE);
162         }
163         g_free(follow_record);
164     }
165     for (cur = follow_info->fragments[1]; cur; cur = g_list_next(cur)) {
166         follow_record = (follow_record_t *)cur->data;
167         if(follow_record->data) {
168             g_byte_array_free(follow_record->data, TRUE);
169         }
170         g_free(follow_record);
171     }
172 
173     free_address(&follow_info->client_ip);
174     free_address(&follow_info->server_ip);
175     g_free(follow_info->filter_out_filter);
176     g_free(follow_info);
177 }
178 
179 tap_packet_status
180 follow_tvb_tap_listener(void *tapdata, packet_info *pinfo,
181                       epan_dissect_t *edt _U_, const void *data)
182 {
183     follow_record_t *follow_record;
184     follow_info_t *follow_info = (follow_info_t *)tapdata;
185     tvbuff_t *next_tvb = (tvbuff_t *)data;
186 
187     follow_record = g_new(follow_record_t,1);
188 
189     follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
190     follow_record->data = g_byte_array_append(follow_record->data,
191                                               tvb_get_ptr(next_tvb, 0, -1),
192                                               tvb_captured_length(next_tvb));
193     follow_record->packet_num = pinfo->fd->num;
194     follow_record->abs_ts = pinfo->fd->abs_ts;
195 
196     if (follow_info->client_port == 0) {
197         follow_info->client_port = pinfo->srcport;
198         copy_address(&follow_info->client_ip, &pinfo->src);
199         follow_info->server_port = pinfo->destport;
200         copy_address(&follow_info->server_ip, &pinfo->dst);
201     }
202 
203     if (addresses_equal(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
204         follow_record->is_server = FALSE;
205     else
206         follow_record->is_server = TRUE;
207 
208     /* update stream counter */
209     follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
210 
211     follow_info->payload = g_list_prepend(follow_info->payload, follow_record);
212     return TAP_PACKET_DONT_REDRAW;
213 }
214 
215 /*
216  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
217  *
218  * Local Variables:
219  * c-basic-offset: 2
220  * tab-width: 8
221  * indent-tabs-mode: nil
222  * End:
223  *
224  * ex: set shiftwidth=2 tabstop=8 expandtab:
225  * :indentSize=2:tabSize=8:noTabs=true:
226  */
227