3 * Copyright 2011, QA Cafe <info@qacafe.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 /* This module provides udp and tcp follow stream capabilities to tshark.
27 * It is only used by tshark and not wireshark.
42 #include <epan/addr_resolv.h>
43 #include <epan/epan_dissect.h>
44 #include <epan/follow.h>
45 #include <epan/stat_cmd_args.h>
47 #include <epan/tvbuff-int.h>
49 #include "wsutil/file_util.h"
52 WS_VAR_IMPORT FILE *data_out_file;
76 guint8 addrBuf[2][16];
82 /* stream chunk file */
87 #define STR_FOLLOW "follow,"
88 #define STR_FOLLOW_TCP STR_FOLLOW "tcp"
89 #define STR_FOLLOW_UDP STR_FOLLOW "udp"
91 #define STR_HEX ",hex"
92 #define STR_ASCII ",ascii"
93 #define STR_RAW ",raw"
100 fprintf(stderr, "tshark: follow - %s\n", strp);
111 case type_TCP: return "tcp";
112 case type_UDP: return "udp";
115 g_assert_not_reached();
117 return "<unknown-type>";
127 case mode_HEX: return "hex";
128 case mode_ASCII: return "ascii";
129 case mode_RAW: return "raw";
132 g_assert_not_reached();
134 return "<unknown-mode>";
142 static char filter[512];
145 gchar ip0[MAX_IP6_STR_LEN];
146 gchar ip1[MAX_IP6_STR_LEN];
148 if (fp->index != G_MAXUINT32)
153 len = g_snprintf(filter, sizeof filter,
154 "tcp.stream eq %d", fp->index);
162 verp = fp->addr[0].type == AT_IPv6 ? "v6" : "";
163 address_to_str_buf(&fp->addr[0], ip0, sizeof ip0);
164 address_to_str_buf(&fp->addr[1], ip1, sizeof ip1);
169 len = g_snprintf(filter, sizeof filter,
170 "((ip%s.src eq %s and tcp.srcport eq %d) and "
171 "(ip%s.dst eq %s and tcp.dstport eq %d))"
173 "((ip%s.src eq %s and tcp.srcport eq %d) and "
174 "(ip%s.dst eq %s and tcp.dstport eq %d))",
175 verp, ip0, fp->port[0],
176 verp, ip1, fp->port[1],
177 verp, ip1, fp->port[1],
178 verp, ip0, fp->port[0]);
181 len = g_snprintf(filter, sizeof filter,
182 "((ip%s.src eq %s and udp.srcport eq %d) and "
183 "(ip%s.dst eq %s and udp.dstport eq %d))"
185 "((ip%s.src eq %s and udp.srcport eq %d) and "
186 "(ip%s.dst eq %s and udp.dstport eq %d))",
187 verp, ip0, fp->port[0],
188 verp, ip1, fp->port[1],
189 verp, ip1, fp->port[1],
190 verp, ip0, fp->port[0]);
197 followExit("Don't know how to create filter.");
200 if (len == sizeof filter)
202 followExit("Filter buffer overflow.");
213 if (fp->filep != NULL)
217 if (fp->type == type_TCP)
219 data_out_file = NULL;
223 if (fp->filenamep != NULL)
225 ws_unlink(fp->filenamep);
226 g_free(fp->filenamep);
227 fp->filenamep = NULL;
239 if (fp->type == type_TCP && data_out_file != NULL)
241 followExit("Only one TCP stream can be followed at a time.");
246 fd = create_tempfile(&tempfilep, "follow");
249 followExit("Error creating temp file.");
252 fp->filenamep = g_strdup(tempfilep);
253 if (fp->filenamep == NULL)
256 ws_unlink(tempfilep);
257 followExit("Error duping temp file name.");
260 fp->filep = fdopen(fd, "w+b");
261 if (fp->filep == NULL)
264 ws_unlink(fp->filenamep);
265 g_free(fp->filenamep);
266 fp->filenamep = NULL;
267 followExit("Error opening temp file stream.");
270 if (fp->type == type_TCP)
272 data_out_file = fp->filep;
283 fp = g_malloc0(sizeof *fp);
286 SET_ADDRESS(&fp->addr[0], AT_NONE, 0, fp->addrBuf[0]);
287 SET_ADDRESS(&fp->addr[1], AT_NONE, 0, fp->addrBuf[1]);
305 epan_dissect_t * edp _U_,
309 follow_t * fp = contextp;
310 const tvbuff_t * tvbp = datap;
314 if (tvbp->length > 0)
316 memcpy(sc.src_addr, pip->net_src.data, pip->net_src.len);
317 sc.src_port = pip->srcport;
318 sc.dlen = tvbp->length;
320 size = fwrite(&sc, 1, sizeof sc, fp->filep);
321 if (sizeof sc != size)
323 followExit("Error writing stream chunk header.");
326 size = fwrite(tvbp->real_data, 1, sc.dlen, fp->filep);
329 followExit("Error writing stream chunk data.");
336 #define BYTES_PER_LINE 16
337 #define OFFSET_START 0
339 #define OFFSET_SPACE 2
340 #define HEX_START (OFFSET_START + OFFSET_LEN + OFFSET_SPACE)
341 #define HEX_LEN (BYTES_PER_LINE * 3) /* extra space at column 8 */
343 #define ASCII_START (HEX_START + HEX_LEN + HEX_SPACE)
344 #define ASCII_LEN (BYTES_PER_LINE + 1) /* extra space at column 8 */
345 #define ASCII_SPACE 0
346 #define LINE_LEN (ASCII_START + ASCII_LEN + ASCII_SPACE)
348 static const char bin2hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
349 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
352 const char * prefixp,
362 char line[LINE_LEN + 1];
364 for (ii = 0, jj = 0, kk = 0; ii < len; )
366 if ((ii % BYTES_PER_LINE) == 0)
369 g_snprintf(line, LINE_LEN + 1, "%0*X", OFFSET_LEN, offset);
370 memset(line + HEX_START - OFFSET_SPACE, ' ',
371 HEX_LEN + OFFSET_SPACE + HEX_SPACE);
376 /* offset of ascii */
380 val = ((guint8 *)datap)[ii];
382 line[jj++] = bin2hex[val >> 4];
383 line[jj++] = bin2hex[val & 0xf];
386 line[kk++] = val >= ' ' && val < 0x7f ? val : '.';
388 /* extra space at column 8 */
389 if (++ii % BYTES_PER_LINE == BYTES_PER_LINE/2)
395 if ((ii % BYTES_PER_LINE) == 0 || ii == len)
397 /* end of line or buffer */
398 if (line[kk - 1] == ' ')
403 printf("%s%s\n", prefixp, line);
404 offset += BYTES_PER_LINE;
414 static const char seperator[] =
415 "===================================================================\n";
417 follow_t * fp = contextp;
420 const address * addr[2];
422 gchar buf[MAX_IP6_STR_LEN];
429 char data[(sizeof bin * 2) + 2];
431 g_assert(sizeof bin % BYTES_PER_LINE == 0);
433 if (fp->type == type_TCP)
435 follow_stats_t stats;
439 follow_stats(&stats);
452 for (node = 0; node < 2; node++)
454 memcpy(fp->addrBuf[node], stats.ip_address[node], len);
455 SET_ADDRESS(&fp->addr[node], type, len, fp->addrBuf[node]);
456 fp->port[node] = stats.port[node];
460 /* find first stream chunk */
464 len = (guint32)fread(&sc, 1, sizeof sc, fp->filep);
465 if (len != sizeof sc)
469 memcpy(sc.src_addr, fp->addr[0].data, fp->addr[0].len) ;
470 sc.src_port = fp->port[0];
480 /* node 0 is source of first chunk with data */
481 if (memcmp(sc.src_addr, fp->addr[0].data, fp->addr[0].len) == 0 &&
482 sc.src_port == fp->port[0])
484 addr[0] = &fp->addr[0];
485 port[0] = fp->port[0];
486 addr[1] = &fp->addr[1];
487 port[1] = fp->port[1];
491 addr[0] = &fp->addr[1];
492 port[0] = fp->port[1];
493 addr[1] = &fp->addr[0];
494 port[1] = fp->port[0];
497 printf("\n%s", seperator);
498 printf("Follow: %s,%s\n", followStrType(fp), followStrMode(fp));
499 printf("Filter: %s\n", followStrFilter(fp));
501 for (node = 0; node < 2; node++)
503 address_to_str_buf(addr[node], buf, sizeof buf);
504 if (addr[node]->type == AT_IPv6)
506 printf("Node %u: [%s]:%d\n", node, buf, port[node]);
510 printf("Node %u: %s:%d\n", node, buf, port[node]);
514 offset[0] = offset[1] = 0;
516 while (chunk <= fp->chunkMax)
518 node = (memcmp(addr[0]->data, sc.src_addr, addr[0]->len) == 0 &&
519 port[0] == sc.src_port) ? 0 : 1;
521 if (chunk < fp->chunkMin)
525 len = sc.dlen < sizeof bin ? sc.dlen : sizeof bin;
527 if (fread(bin, 1, len, fp->filep) != len)
529 followExit("Error reading stream chunk data.");
542 printf("%s%d\n", node ? "\t" : "", sc.dlen);
555 len = sc.dlen < sizeof bin ? sc.dlen : sizeof bin;
557 if (fread(bin, 1, len, fp->filep) != len)
559 followExit("Error reading stream chunk data.");
565 followPrintHex(node ? "\t" : "", offset[node], bin, len);
569 for (ii = 0; ii < len; ii++)
578 data[ii] = isprint(bin[ii]) ? bin[ii] : '.';
591 for (ii = 0, jj = 0; ii < len; ii++)
593 data[jj++] = bin2hex[bin[ii] >> 4];
594 data[jj++] = bin2hex[bin[ii] & 0xf];
610 len = (guint32)fread(&sc, 1, sizeof sc, fp->filep);
611 if (len != sizeof sc)
628 printf("%s", seperator);
635 const char ** optargp,
639 int len = (guint32)strlen(strp);
641 if (strncmp(*optargp, strp, len) == 0)
651 const char ** optargp,
655 if (followArgStrncmp(optargp, STR_HEX))
659 else if (followArgStrncmp(optargp, STR_ASCII))
661 fp->mode = mode_ASCII;
663 else if (followArgStrncmp(optargp, STR_RAW))
669 followExit("Invalid display mode.");
675 const char ** optargp,
679 #define _STRING(s) # s
680 #define STRING(s) _STRING(s)
682 #define ADDR_CHARS 80
683 #define ADDR_LEN (ADDR_CHARS + 1)
684 #define ADDRv6_FMT ",[%" STRING(ADDR_CHARS) "[^]]]:%d%n"
685 #define ADDRv4_FMT ",%" STRING(ADDR_CHARS) "[^:]:%d%n"
691 if (sscanf(*optargp, ",%u%n", &fp->index, &len) == 1 &&
692 ((*optargp)[len] == 0 || (*optargp)[len] == ','))
698 for (ii = 0; ii < sizeof fp->addr/sizeof *fp->addr; ii++)
700 if ((sscanf(*optargp, ADDRv6_FMT, addr, &fp->port[ii], &len) != 2 &&
701 sscanf(*optargp, ADDRv4_FMT, addr, &fp->port[ii], &len) != 2) ||
702 fp->port[ii] <= 0 || fp->port[ii] > G_MAXUINT16)
704 followExit("Invalid address:port pair.");
707 if (strcmp("ip6", host_ip_af(addr)) == 0)
709 if (!get_host_ipaddr6(addr, (struct e_in6_addr *)fp->addrBuf[ii]))
711 followExit("Can't get IPv6 address");
713 SET_ADDRESS(&fp->addr[ii], AT_IPv6, 16, fp->addrBuf[ii]);
717 if (!get_host_ipaddr(addr, (guint32 *)fp->addrBuf[ii]))
719 followExit("Can't get IPv4 address");
721 SET_ADDRESS(&fp->addr[ii], AT_IPv4, 4, fp->addrBuf[ii]);
727 if (fp->addr[0].type != fp->addr[1].type)
729 followExit("Mismatched IP address types.");
731 fp->index = G_MAXUINT32;
737 const char ** optargp,
746 fp->chunkMax = G_MAXUINT32;
750 if (sscanf(*optargp, ",%u-%u%n", &fp->chunkMin, &fp->chunkMax, &len) == 2)
754 else if (sscanf(*optargp, ",%u%n", &fp->chunkMin, &len) == 1)
756 fp->chunkMax = fp->chunkMin;
761 followExit("Invalid range.");
764 if (fp->chunkMin < 1 || fp->chunkMin > fp->chunkMax)
766 followExit("Invalid range value.");
778 followExit("Invalid parameter.");
791 optarg += strlen(STR_FOLLOW_TCP);
793 fp = followAlloc(type_TCP);
795 followArgMode(&optarg, fp);
796 followArgFilter(&optarg, fp);
797 followArgRange(&optarg, fp);
798 followArgDone(optarg);
800 reset_tcp_reassembly();
801 if (fp->index != G_MAXUINT32)
803 if (!follow_tcp_index(fp->index))
805 followExit("Can't follow tcp index.");
810 if (!follow_tcp_addr(&fp->addr[0], fp->port[0],
811 &fp->addr[1], fp->port[1]))
813 followExit("Can't follow tcp address/port pairs.");
819 errp = register_tap_listener("frame", fp, NULL, 0,
820 NULL, NULL, followDraw);
824 g_string_free(errp, TRUE);
825 followExit("Error registering tcp tap listner.");
838 optarg += strlen(STR_FOLLOW_UDP);
840 fp = followAlloc(type_UDP);
842 followArgMode(&optarg, fp);
843 followArgFilter(&optarg, fp);
844 followArgRange(&optarg, fp);
845 followArgDone(optarg);
847 if (fp->index != G_MAXUINT32)
849 followExit("UDP does not support index filters.");
854 errp = register_tap_listener("udp_follow", fp, followStrFilter(fp), 0,
855 NULL, followPacket, followDraw);
859 g_string_free(errp, TRUE);
860 followExit("Error registering udp tap listner.");
865 register_tap_listener_follow(void)
867 register_stat_cmd_arg(STR_FOLLOW_TCP, followTcp, NULL);
868 register_stat_cmd_arg(STR_FOLLOW_UDP, followUdp, NULL);