2 * TCP specific routines for following traffic streams
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
41 #include <epan/follow.h>
42 #include <epan/dissectors/packet-ipv6.h>
43 #include <epan/prefs.h>
44 #include <epan/addr_resolv.h>
45 #include <epan/charsets.h>
46 #include <epan/epan_dissect.h>
47 #include <epan/filesystem.h>
48 #include <epan/ipproto.h>
49 #include <epan/charsets.h>
51 #include "../isprint.h"
54 #include "../globals.h"
55 #include "../alert_box.h"
56 #include "../simple_dialog.h"
57 #include "../tempfile.h"
58 #include <wsutil/file_util.h>
60 #include "gtk/color_utils.h"
61 #include "gtk/follow_tcp.h"
62 #include "gtk/dlg_utils.h"
63 #include "gtk/file_dlg.h"
66 #include "gtk/gui_utils.h"
67 #include "gtk/print_win32.h"
68 #include "gtk/font_utils.h"
69 #include "gtk/help_dlg.h"
70 #include "gtk/follow_stream.h"
73 /* With MSVC and a libwireshark.dll, we need a special declaration. */
74 WS_VAR_IMPORT FILE *data_out_file;
77 follow_redraw(gpointer data, gpointer user_data _U_)
79 follow_load_text((follow_info_t *)data);
82 /* Redraw the text in all "Follow TCP Stream" windows. */
84 follow_tcp_redraw_all(void)
86 g_list_foreach(follow_infos, follow_redraw, NULL);
89 /* Follow the TCP stream, if any, to which the last packet that we called
90 a dissection routine on belongs (this might be the most recently
91 selected packet, or it might be the last packet in the file). */
93 follow_tcp_stream_cb(GtkWidget * w, gpointer data _U_)
98 const gchar *previous_filter;
99 int filter_out_filter_len;
100 const char *hostname0, *hostname1;
102 gchar *server_to_client_string = NULL;
103 gchar *client_to_server_string = NULL;
104 gchar *both_directions_string = NULL;
105 follow_stats_t stats;
106 follow_info_t *follow_info;
109 gchar *data_out_filename;
111 /* we got tcp so we can follow */
112 if (cfile.edt->pi.ipproto != IP_PROTO_TCP) {
113 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
114 "Error following stream. Please make\n"
115 "sure you have a TCP packet selected.");
119 follow_info = g_new0(follow_info_t, 1);
120 follow_info->follow_type = FOLLOW_TCP;
122 /* Create a new filter that matches all packets in the TCP stream,
123 and set the display filter entry accordingly */
124 reset_tcp_reassembly();
125 follow_filter = build_follow_filter(&cfile.edt->pi);
126 if (!follow_filter) {
127 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
128 "Error creating filter for this stream.\n"
129 "A transport or network layer header is needed");
134 /* Create a temporary file into which to dump the reassembled data
135 from the TCP stream, and set "data_out_file" to refer to it, so
136 that the TCP code will write to it.
138 XXX - it might be nicer to just have the TCP code directly
139 append stuff to the text widget for the TCP stream window,
140 if we can arrange that said window not pop up until we're
142 tmp_fd = create_tempfile(&data_out_filename, "follow");
143 follow_info->data_out_filename = g_strdup(data_out_filename);
146 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
147 "Could not create temporary file %s: %s",
148 follow_info->data_out_filename, strerror(errno));
149 g_free(follow_info->data_out_filename);
151 g_free(follow_filter);
155 data_out_file = fdopen(tmp_fd, "w+b");
156 if (data_out_file == NULL) {
157 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
158 "Could not create temporary file %s: %s",
159 follow_info->data_out_filename, strerror(errno));
161 ws_unlink(follow_info->data_out_filename);
162 g_free(follow_info->data_out_filename);
164 g_free(follow_filter);
168 /* Set the display filter entry accordingly */
169 filter_te = g_object_get_data(G_OBJECT(w), E_DFILTER_TE_KEY);
171 /* needed in follow_filter_out_stream(), is there a better way? */
172 follow_info->filter_te = filter_te;
174 /* save previous filter, const since we're not supposed to alter */
176 (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
178 /* allocate our new filter. API claims g_malloc terminates program on failure */
179 /* my calc for max alloc needed is really +10 but when did a few extra bytes hurt ? */
180 filter_out_filter_len = (int)(strlen(follow_filter) + strlen(previous_filter) + 16);
181 follow_info->filter_out_filter = (gchar *)g_malloc(filter_out_filter_len);
183 /* append the negation */
184 if(strlen(previous_filter)) {
185 g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
186 "%s and !(%s)", previous_filter, follow_filter);
188 g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
189 "!(%s)", follow_filter);
192 gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
194 /* Run the display filter so it goes in effect - even if it's the
195 same as the previous display filter. */
196 main_filter_packets(&cfile, follow_filter, TRUE);
198 /* Free the filter string, as we're done with it. */
199 g_free(follow_filter);
201 /* Check whether we got any data written to the file. */
202 if (empty_tcp_stream) {
203 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
204 "The packets in the capture file for that stream have no data.");
206 ws_unlink(follow_info->data_out_filename);
207 g_free(follow_info->data_out_filename);
208 g_free(follow_info->filter_out_filter);
213 /* Go back to the top of the file and read the first tcp_stream_chunk
214 * to ensure that the IP addresses and port numbers in the drop-down
215 * list are tied to the correct lines displayed by follow_read_stream()
216 * later on (which also reads from this file). Close the file when
219 * We read the data now, before we pop up a window, in case the
220 * read fails. We use the data later.
223 rewind(data_out_file);
224 nchars=fread(&sc, 1, sizeof(sc), data_out_file);
225 if (nchars != sizeof(sc)) {
226 if (ferror(data_out_file)) {
227 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
228 "Could not read from temporary file %s: %s",
229 follow_info->data_out_filename, strerror(errno));
231 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
232 "Short read from temporary file %s: expected %lu, got %lu",
233 follow_info->data_out_filename,
234 (unsigned long)sizeof(sc),
235 (unsigned long)nchars);
238 ws_unlink(follow_info->data_out_filename);
239 g_free(follow_info->data_out_filename);
240 g_free(follow_info->filter_out_filter);
244 fclose(data_out_file);
246 /* The data_out_filename file now has all the text that was in the
247 session (this is dumped to file by the TCP dissector). */
250 follow_stats(&stats);
253 struct e_in6_addr ipaddr;
254 memcpy(&ipaddr, stats.ip_address[0], 16);
255 hostname0 = get_hostname6(&ipaddr);
256 memcpy(&ipaddr, stats.ip_address[0], 16);
257 hostname1 = get_hostname6(&ipaddr);
260 memcpy(&ipaddr, stats.ip_address[0], 4);
261 hostname0 = get_hostname(ipaddr);
262 memcpy(&ipaddr, stats.ip_address[1], 4);
263 hostname1 = get_hostname(ipaddr);
266 follow_info->is_ipv6 = stats.is_ipv6;
268 port0 = get_tcp_port(stats.port[0]);
269 port1 = get_tcp_port(stats.port[1]);
271 /* Host 0 --> Host 1 */
272 if(sc.src_port == stats.port[0]) {
273 server_to_client_string =
274 g_strdup_printf("%s:%s --> %s:%s (%u bytes)",
277 stats.bytes_written[0]);
279 server_to_client_string =
280 g_strdup_printf("%s:%s --> %s:%s (%u bytes)",
283 stats.bytes_written[0]);
286 /* Host 1 --> Host 0 */
287 if(sc.src_port == stats.port[1]) {
288 client_to_server_string =
289 g_strdup_printf("%s:%s --> %s:%s (%u bytes)",
292 stats.bytes_written[1]);
294 client_to_server_string =
295 g_strdup_printf("%s:%s --> %s:%s (%u bytes)",
298 stats.bytes_written[1]);
301 /* Both Stream Directions */
302 both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", stats.bytes_written[0] + stats.bytes_written[1]);
304 follow_stream("Follow TCP Stream", follow_info, both_directions_string,
305 server_to_client_string, client_to_server_string);
307 g_free(both_directions_string);
308 g_free(server_to_client_string);
309 g_free(client_to_server_string);
311 data_out_file = NULL;
314 #define FLT_BUF_SIZE 1024
317 * XXX - the routine pointed to by "print_line_fcn_p" doesn't get handed lines,
318 * it gets handed bufferfuls. That's fine for "follow_write_raw()"
319 * and "follow_add_to_gtk_text()", but, as "follow_print_text()" calls
320 * the "print_line()" routine from "print.c", and as that routine might
321 * genuinely expect to be handed a line (if, for example, it's using
322 * some OS or desktop environment's printing API, and that API expects
323 * to be handed lines), "follow_print_text()" should probably accumulate
324 * lines in a buffer and hand them "print_line()". (If there's a
325 * complete line in a buffer - i.e., there's nothing of the line in
326 * the previous buffer or the next buffer - it can just hand that to
327 * "print_line()" after filtering out non-printables, as an
330 * This might or might not be the reason why C arrays display
331 * correctly but get extra blank lines very other line when printed.
334 follow_read_tcp_stream(follow_info_t *follow_info,
335 gboolean (*print_line_fcn_p)(char *, size_t, gboolean, void *),
340 guint8 client_addr[MAX_IPADDR_LEN];
341 guint16 client_port = 0;
343 guint32 global_client_pos = 0, global_server_pos = 0;
344 guint32 server_packet_count = 0;
345 guint32 client_packet_count = 0;
348 char buffer[FLT_BUF_SIZE+1]; /* +1 to fix ws bug 1043 */
350 frs_return_t frs_return;
352 iplen = (follow_info->is_ipv6) ? 16 : 4;
354 data_out_file = ws_fopen(follow_info->data_out_filename, "rb");
355 if (data_out_file == NULL) {
356 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
357 "Could not open temporary file %s: %s", follow_info->data_out_filename,
359 return FRS_OPEN_ERROR;
362 while ((nchars=fread(&sc, 1, sizeof(sc), data_out_file))) {
363 if (nchars != sizeof(sc)) {
364 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
365 "Short read from temporary file %s: expected %lu, got %lu",
366 follow_info->data_out_filename,
367 (unsigned long)sizeof(sc),
368 (unsigned long)nchars);
369 fclose(data_out_file);
370 data_out_file = NULL;
371 return FRS_READ_ERROR;
373 if (client_port == 0) {
374 memcpy(client_addr, sc.src_addr, iplen);
375 client_port = sc.src_port;
378 if (memcmp(client_addr, sc.src_addr, iplen) == 0 &&
379 client_port == sc.src_port) {
381 global_pos = &global_client_pos;
382 if (follow_info->show_stream == FROM_SERVER) {
388 global_pos = &global_server_pos;
389 if (follow_info->show_stream == FROM_CLIENT) {
394 while (sc.dlen > 0) {
395 bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
396 nchars = fread(buffer, 1, bcount, data_out_file);
399 /* XXX - if we don't get "bcount" bytes, is that an error? */
400 sc.dlen -= (guint32) nchars;
403 frs_return = follow_show(follow_info, print_line_fcn_p, buffer,
404 nchars, is_server, arg, global_pos,
405 &server_packet_count,
406 &client_packet_count);
407 if(frs_return == FRS_PRINT_ERROR) {
408 fclose(data_out_file);
409 data_out_file = NULL;
417 if (ferror(data_out_file)) {
418 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
419 "Error reading temporary file %s: %s", follow_info->data_out_filename,
421 fclose(data_out_file);
422 data_out_file = NULL;
423 return FRS_READ_ERROR;
426 fclose(data_out_file);
427 data_out_file = NULL;