5f911a04e27a98fd7814135f0503f437d774d8cb
[metze/wireshark/wip.git] / ui / gtk / follow_udp.c
1 /* follow_udp.c
2  * UDP specific routines for following traffic streams
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
21  * USA.
22  */
23
24 #include "config.h"
25 #include <string.h>
26
27 #include <gtk/gtk.h>
28
29 #include <epan/addr_resolv.h>
30 #include <epan/epan_dissect.h>
31 #include <epan/follow.h>
32 #include <epan/strutil.h>
33 #include <epan/tap.h>
34
35 #include <ui/simple_dialog.h>
36 #include <ui/utf8_entities.h>
37
38 #include "gtkglobals.h"
39 #include "ui/follow.h"
40 #include "ui/gtk/follow_stream.h"
41 #include "ui/gtk/keys.h"
42 #include "ui/gtk/main.h"
43 #include "ui/gtk/follow_udp.h"
44
45 static int
46 udp_queue_packet_data(void *tapdata, packet_info *pinfo,
47                       epan_dissect_t *edt _U_, const void *data)
48 {
49     follow_record_t *follow_record;
50     follow_info_t *follow_info = (follow_info_t *)tapdata;
51     tvbuff_t *next_tvb = (tvbuff_t *)data;
52
53     follow_record = g_new(follow_record_t,1);
54
55     follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb));
56     follow_record->data = g_byte_array_append(follow_record->data,
57                                               tvb_get_ptr(next_tvb, 0, -1),
58                                               tvb_captured_length(next_tvb));
59
60     if (follow_info->client_port == 0) {
61         follow_info->client_port = pinfo->srcport;
62         COPY_ADDRESS(&follow_info->client_ip, &pinfo->src);
63     }
64
65     if (ADDRESSES_EQUAL(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport)
66         follow_record->is_server = FALSE;
67     else
68         follow_record->is_server = TRUE;
69
70     /* update stream counter */
71     follow_info->bytes_written[follow_record->is_server] += follow_record->data->len;
72
73     follow_info->payload = g_list_append(follow_info->payload, follow_record);
74     return 0;
75 }
76
77 /* Follow the UDP stream, if any, to which the last packet that we called
78    a dissection routine on belongs (this might be the most recently
79    selected packet, or it might be the last packet in the file). */
80 void
81 follow_udp_stream_cb(GtkWidget *w _U_, gpointer data _U_)
82 {
83     GtkWidget *filter_te, *filter_cm;
84     gchar *follow_filter;
85     const gchar *previous_filter;
86     int filter_out_filter_len, previous_filter_len;
87     const char *hostname0, *hostname1;
88     char *port0, *port1;
89     gchar *server_to_client_string = NULL;
90     gchar *client_to_server_string = NULL;
91     gchar *both_directions_string = NULL;
92     follow_stats_t stats;
93     follow_info_t *follow_info;
94     GString *msg;
95     gboolean is_udp = FALSE;
96
97     is_udp = proto_is_frame_protocol(cfile.edt->pi.layers, "udp");
98
99     if (!is_udp) {
100         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
101                       "Error following stream.  Please make\n"
102                       "sure you have a UDP packet selected.");
103         return;
104     }
105
106     follow_info = g_new0(follow_info_t, 1);
107     follow_info->follow_type = FOLLOW_UDP;
108
109     /* Create a new filter that matches all packets in the UDP stream,
110        and set the display filter entry accordingly */
111     follow_filter = build_follow_conv_filter(&cfile.edt->pi);
112     if (!follow_filter)
113         {
114             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
115                           "Error creating filter for this stream.\n"
116                           "A network layer header is needed");
117             g_free(follow_info);
118             return;
119         }
120
121     /* Set the display filter entry accordingly */
122     filter_cm = (GtkWidget *)g_object_get_data(G_OBJECT(top_level), E_DFILTER_CM_KEY);
123     filter_te = gtk_bin_get_child(GTK_BIN(filter_cm));
124
125     /* needed in follow_filter_out_stream(), is there a better way? */
126     follow_info->filter_te = filter_te;
127
128     /* save previous filter, const since we're not supposed to alter */
129     previous_filter =
130         (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
131
132     /* allocate our new filter. API claims g_malloc terminates program on failure */
133     /* my calc for max alloc needed is really +10 but when did a few extra bytes hurt ? */
134     previous_filter_len = previous_filter?(int)strlen(previous_filter):0;
135     filter_out_filter_len = (int)strlen(follow_filter) + previous_filter_len + 16;
136     follow_info->filter_out_filter = (gchar *)g_malloc(filter_out_filter_len);
137
138     /* append the negation */
139     if(previous_filter_len) {
140         g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
141                    "%s and !(%s)", previous_filter, follow_filter);
142     } else {
143         g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
144                    "!(%s)", follow_filter);
145     }
146
147     /* data will be passed via tap callback*/
148     msg = register_tap_listener("udp_follow", follow_info, follow_filter,
149                                 0, NULL, udp_queue_packet_data, NULL);
150     if (msg) {
151         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
152                       "Can't register udp_follow tap: %s\n",
153                       msg->str);
154         g_free(follow_info->filter_out_filter);
155         g_free(follow_info);
156         g_free(follow_filter);
157         return;
158     }
159
160     gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
161
162     /* Run the display filter so it goes in effect - even if it's the
163        same as the previous display filter. */
164     main_filter_packets(&cfile, follow_filter, TRUE);
165
166     /* Free the filter string, as we're done with it. */
167     g_free(follow_filter);
168
169     remove_tap_listener(follow_info);
170
171     /* Stream to show */
172     follow_stats(&stats);
173
174     if (stats.is_ipv6) {
175         struct e_in6_addr ipaddr;
176         memcpy(&ipaddr, stats.ip_address[0], 16);
177         hostname0 = get_hostname6(&ipaddr);
178         memcpy(&ipaddr, stats.ip_address[1], 16);
179         hostname1 = get_hostname6(&ipaddr);
180     } else {
181         guint32 ipaddr;
182         memcpy(&ipaddr, stats.ip_address[0], 4);
183         hostname0 = get_hostname(ipaddr);
184         memcpy(&ipaddr, stats.ip_address[1], 4);
185         hostname1 = get_hostname(ipaddr);
186     }
187
188     port0 = ep_udp_port_to_display(stats.port[0]);
189     port1 = ep_udp_port_to_display(stats.port[1]);
190
191     follow_info->is_ipv6 = stats.is_ipv6;
192
193     /* Both Stream Directions */
194     both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", follow_info->bytes_written[0] + follow_info->bytes_written[1]);
195
196     if ((follow_info->client_port == stats.port[0]) &&
197         ((stats.is_ipv6 && (memcmp(follow_info->client_ip.data, stats.ip_address[0], 16) == 0)) ||
198          (!stats.is_ipv6 && (memcmp(follow_info->client_ip.data, stats.ip_address[0], 4) == 0)))) {
199         server_to_client_string =
200             g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
201                             hostname0, port0,
202                             hostname1, port1,
203                             follow_info->bytes_written[0]);
204
205         client_to_server_string =
206             g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
207                             hostname1, port1,
208                             hostname0, port0,
209                             follow_info->bytes_written[1]);
210     } else {
211         server_to_client_string =
212             g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
213                             hostname1, port1,
214                             hostname0, port0,
215                             follow_info->bytes_written[0]);
216
217         client_to_server_string =
218             g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
219                             hostname0, port0,
220                             hostname1, port1,
221                             follow_info->bytes_written[1]);
222     }
223
224     follow_stream("Follow UDP Stream", follow_info, both_directions_string,
225                   server_to_client_string, client_to_server_string);
226
227     g_free(both_directions_string);
228     g_free(server_to_client_string);
229     g_free(client_to_server_string);
230 }
231
232 #define FLT_BUF_SIZE 1024
233
234 /*
235  * XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
236  * it gets handed bufferfuls.  That's fine for "follow_write_raw()"
237  * and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
238  * the "print_line()" routine from "print.c", and as that routine might
239  * genuinely expect to be handed a line (if, for example, it's using
240  * some OS or desktop environment's printing API, and that API expects
241  * to be handed lines), "follow_print_text()" should probably accumulate
242  * lines in a buffer and hand them "print_line()".  (If there's a
243  * complete line in a buffer - i.e., there's nothing of the line in
244  * the previous buffer or the next buffer - it can just hand that to
245  * "print_line()" after filtering out non-printables, as an
246  * optimization.)
247  *
248  * This might or might not be the reason why C arrays display
249  * correctly but get extra blank lines very other line when printed.
250  */
251 frs_return_t
252 follow_read_udp_stream(follow_info_t *follow_info,
253                        gboolean (*print_line_fcn_p)(char *, size_t, gboolean, void *),
254                        void *arg)
255 {
256     guint32 global_client_pos = 0, global_server_pos = 0;
257     guint32 server_packet_count = 0;
258     guint32 client_packet_count = 0;
259     guint32 *global_pos;
260     gboolean skip;
261     GList* cur;
262     frs_return_t frs_return;
263     follow_record_t *follow_record;
264     char *buffer;
265
266
267     for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
268         follow_record = (follow_record_t *)cur->data;
269         skip = FALSE;
270         if (!follow_record->is_server) {
271             global_pos = &global_client_pos;
272             if(follow_info->show_stream == FROM_SERVER) {
273                 skip = TRUE;
274             }
275         } else {
276             global_pos = &global_server_pos;
277             if (follow_info->show_stream == FROM_CLIENT) {
278                 skip = TRUE;
279             }
280         }
281
282         if (!skip) {
283             buffer = (char *)g_memdup(follow_record->data->data,
284                                      follow_record->data->len);
285
286             frs_return = follow_show(follow_info, print_line_fcn_p,
287                                      buffer,
288                                      follow_record->data->len,
289                                      follow_record->is_server, arg,
290                                      global_pos,
291                                      &server_packet_count,
292                                      &client_packet_count);
293             g_free(buffer);
294             if(frs_return == FRS_PRINT_ERROR)
295                 return frs_return;
296         }
297     }
298
299     return FRS_OK;
300 }
301
302 /*
303  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
304  *
305  * Local variables:
306  * c-basic-offset: 4
307  * tab-width: 8
308  * indent-tabs-mode: nil
309  * End:
310  *
311  * vi: set shiftwidth=4 tabstop=8 expandtab:
312  * :indentSize=4:tabSize=8:noTabs=true:
313  */