Get rid of -Wshadow warning - I guess we're including something that
[metze/wireshark/wip.git] / ui / cli / tap-follow.c
1 /* tap-follow.c
2  *
3  * Copyright 2011-2013, QA Cafe <info@qacafe.com>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
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.
15  *
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.
20  *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 /* This module provides udp and tcp follow stream capabilities to tshark.
27  * It is only used by tshark and not wireshark.
28  */
29
30 #include "config.h"
31 #include "ws_symbol_export.h"
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #include <ctype.h>
38 #include <stdio.h>
39
40 #include <glib.h>
41 #include <epan/addr_resolv.h>
42 #include <epan/epan_dissect.h>
43 #include <epan/follow.h>
44 #include <epan/stat_cmd_args.h>
45 #include <epan/tap.h>
46 #include <epan/tvbuff-int.h>
47
48 #include "wsutil/file_util.h"
49 #include "wsutil/tempfile.h"
50
51 #ifdef SSL_PLUGIN
52 #include "packet-ssl-utils.h"
53 #else
54 #include <epan/dissectors/packet-ssl-utils.h>
55 #endif
56
57 WS_DLL_PUBLIC FILE *data_out_file;
58
59 typedef enum
60 {
61   type_TCP,
62   type_UDP,
63   type_SSL
64 } type_e;
65
66 typedef enum
67 {
68   mode_HEX,
69   mode_ASCII,
70   mode_RAW
71 } mode_e;
72
73 typedef struct
74 {
75   type_e        type;
76   mode_e        mode;
77
78   /* filter */
79   guint32       index;
80   address       addr[2];
81   int           port[2];
82   guint8        addrBuf[2][16];
83
84   /* range */
85   guint32       chunkMin;
86   guint32       chunkMax;
87
88   /* stream chunk file */
89   FILE *        filep;
90   gchar *       filenamep;
91 } follow_t;
92
93 #define STR_FOLLOW      "follow,"
94 #define STR_FOLLOW_TCP  STR_FOLLOW "tcp"
95 #define STR_FOLLOW_UDP  STR_FOLLOW "udp"
96 #define STR_FOLLOW_SSL  STR_FOLLOW "ssl"
97
98 #define STR_HEX         ",hex"
99 #define STR_ASCII       ",ascii"
100 #define STR_RAW         ",raw"
101
102 static void
103 followExit(
104   const char *  strp
105   )
106 {
107   fprintf(stderr, "tshark: follow - %s\n", strp);
108   exit(1);
109 }
110
111 static const char *
112 followStrType(
113   const follow_t *      fp
114   )
115 {
116   switch (fp->type)
117   {
118   case type_TCP:        return "tcp";
119   case type_UDP:        return "udp";
120   case type_SSL:        return "ssl";
121   }
122
123   g_assert_not_reached();
124
125   return "<unknown-type>";
126 }
127
128 static const char *
129 followStrMode(
130   const follow_t *      fp
131   )
132 {
133   switch (fp->mode)
134   {
135   case mode_HEX:        return "hex";
136   case mode_ASCII:      return "ascii";
137   case mode_RAW:        return "raw";
138   }
139
140   g_assert_not_reached();
141
142   return "<unknown-mode>";
143 }
144
145 static const char *
146 followStrFilter(
147   const follow_t *      fp
148   )
149 {
150   static char   filter[512];
151   int           len     = 0;
152   const gchar * verp;
153   gchar         ip0[MAX_IP6_STR_LEN];
154   gchar         ip1[MAX_IP6_STR_LEN];
155
156   if (fp->index != G_MAXUINT32)
157   {
158     switch (fp->type)
159     {
160     case type_TCP:
161     case type_SSL:
162       len = g_snprintf(filter, sizeof filter,
163                      "tcp.stream eq %d", fp->index);
164       break;
165     case type_UDP:
166       break;
167     }
168   }
169   else
170   {
171     verp = fp->addr[0].type == AT_IPv6 ? "v6" : "";
172     address_to_str_buf(&fp->addr[0], ip0, sizeof ip0);
173     address_to_str_buf(&fp->addr[1], ip1, sizeof ip1);
174
175     switch (fp->type)
176     {
177     case type_TCP:
178       len = g_snprintf(filter, sizeof filter,
179                      "((ip%s.src eq %s and tcp.srcport eq %d) and "
180                      "(ip%s.dst eq %s and tcp.dstport eq %d))"
181                      " or "
182                      "((ip%s.src eq %s and tcp.srcport eq %d) and "
183                      "(ip%s.dst eq %s and tcp.dstport eq %d))",
184                      verp, ip0, fp->port[0],
185                      verp, ip1, fp->port[1],
186                      verp, ip1, fp->port[1],
187                      verp, ip0, fp->port[0]);
188       break;
189     case type_UDP:
190       len = g_snprintf(filter, sizeof filter,
191                      "((ip%s.src eq %s and udp.srcport eq %d) and "
192                      "(ip%s.dst eq %s and udp.dstport eq %d))"
193                      " or "
194                      "((ip%s.src eq %s and udp.srcport eq %d) and "
195                      "(ip%s.dst eq %s and udp.dstport eq %d))",
196                      verp, ip0, fp->port[0],
197                      verp, ip1, fp->port[1],
198                      verp, ip1, fp->port[1],
199                      verp, ip0, fp->port[0]);
200       break;
201     case type_SSL:
202       break;
203     }
204   }
205
206   if (len == 0)
207   {
208     followExit("Don't know how to create filter.");
209   }
210
211   if (len == sizeof filter)
212   {
213     followExit("Filter buffer overflow.");
214   }
215
216   return filter;
217 }
218
219 static void
220 followFileClose(
221   follow_t *    fp
222   )
223 {
224   if (fp->filep != NULL)
225   {
226     fclose(fp->filep);
227     fp->filep = NULL;
228     if (fp->type == type_TCP)
229     {
230       data_out_file = NULL;
231     }
232   }
233
234   if (fp->filenamep != NULL)
235   {
236     ws_unlink(fp->filenamep);
237     g_free(fp->filenamep);
238     fp->filenamep = NULL;
239   }
240 }
241
242 static void
243 followFileOpen(
244   follow_t *    fp
245   )
246 {
247   int           fd;
248   char *        tempfilep;
249
250   if (fp->type == type_TCP && data_out_file != NULL)
251   {
252     followExit("Only one TCP stream can be followed at a time.");
253   }
254
255   followFileClose(fp);
256
257   fd = create_tempfile(&tempfilep, "follow");
258   if (fd == -1)
259   {
260     followExit("Error creating temp file.");
261   }
262
263   fp->filenamep = g_strdup(tempfilep);
264   if (fp->filenamep == NULL)
265   {
266     ws_close(fd);
267     ws_unlink(tempfilep);
268     followExit("Error duping temp file name.");
269   }
270
271   fp->filep = fdopen(fd, "w+b");
272   if (fp->filep == NULL)
273   {
274     ws_close(fd);
275     ws_unlink(fp->filenamep);
276     g_free(fp->filenamep);
277     fp->filenamep = NULL;
278     followExit("Error opening temp file stream.");
279   }
280
281   if (fp->type == type_TCP)
282   {
283     data_out_file = fp->filep;
284   }
285 }
286
287 static follow_t *
288 followAlloc(
289   type_e        type
290   )
291 {
292   follow_t *    fp;
293
294   fp = (follow_t *)g_malloc0(sizeof *fp);
295
296   fp->type = type;
297   SET_ADDRESS(&fp->addr[0], AT_NONE, 0, fp->addrBuf[0]);
298   SET_ADDRESS(&fp->addr[1], AT_NONE, 0, fp->addrBuf[1]);
299
300   return fp;
301 }
302
303 static void
304 followFree(
305   follow_t *    fp
306   )
307 {
308   followFileClose(fp);
309   g_free(fp);
310 }
311
312 static int
313 followUdpPacket(
314   void *                contextp,
315   packet_info *         pip,
316   epan_dissect_t *      edp _U_,
317   const void *          datap
318   )
319 {
320   follow_t *            fp      = (follow_t *)contextp;
321   const tvbuff_t *      tvbp    = (const tvbuff_t *)datap;
322   tcp_stream_chunk      sc;
323   size_t                size;
324
325   if (tvbp->length > 0)
326   {
327     memcpy(sc.src_addr, pip->net_src.data, pip->net_src.len);
328     sc.src_port = pip->srcport;
329     sc.dlen     = tvbp->length;
330
331     size = fwrite(&sc, 1, sizeof sc, fp->filep);
332     if (sizeof sc != size)
333     {
334       followExit("Error writing stream chunk header.");
335     }
336
337     size = fwrite(tvbp->real_data, 1, sc.dlen, fp->filep);
338     if (sc.dlen != size)
339     {
340       followExit("Error writing stream chunk data.");
341     }
342   }
343
344   return 0;
345 }
346
347 static int
348 followSslPacket(
349   void *                contextp,
350   packet_info *         pip,
351   epan_dissect_t *      edp _U_,
352   const void *          datap
353   )
354 {
355   follow_t *            fp      = (follow_t *)contextp;
356   SslPacketInfo *       spip    = (SslPacketInfo *)p_get_proto_data(pip->fd, GPOINTER_TO_INT(datap), 0);
357   SslDataInfo *         sdip;
358   gint                  length;
359   tcp_stream_chunk      sc;
360   size_t                size;
361
362   if (spip == NULL)
363   {
364     return 0;
365   }
366
367   if (fp->addr[0].type == AT_NONE)
368   {
369     memcpy(fp->addrBuf[0], pip->net_src.data, pip->net_src.len);
370     SET_ADDRESS(&fp->addr[0], pip->net_src.type, pip->net_src.len,
371                 fp->addrBuf[0]);
372     fp->port[0] = pip->srcport;
373
374     memcpy(fp->addrBuf[1], pip->net_dst.data, pip->net_dst.len);
375     SET_ADDRESS(&fp->addr[1], pip->net_dst.type, pip->net_dst.len,
376                 fp->addrBuf[1]);
377     fp->port[1] = pip->destport;
378   }
379
380   /* total length */
381   for (length = 0, sdip = spip->appl_data; sdip != NULL; sdip = sdip->next)
382   {
383     length += sdip->plain_data.data_len;
384   }
385
386
387   if (length > 0)
388   {
389     memcpy(sc.src_addr, pip->net_src.data, pip->net_src.len);
390     sc.src_port = pip->srcport;
391     sc.dlen     = length;
392
393     size = fwrite(&sc, 1, sizeof sc, fp->filep);
394     if (sizeof sc != size)
395     {
396       followExit("Error writing stream chunk header.");
397     }
398
399     for (sdip = spip->appl_data; sdip != NULL; sdip = sdip->next)
400     {
401       if (sdip->plain_data.data_len > 0)
402       {
403         size = fwrite(sdip->plain_data.data, 1, sdip->plain_data.data_len,
404                       fp->filep);
405         if (sdip->plain_data.data_len != size)
406         {
407           followExit("Error writing stream chunk data.");
408         }
409       }
410     }
411   }
412
413   return 0;
414 }
415
416 #define BYTES_PER_LINE  16
417 #define OFFSET_START    0
418 #define OFFSET_LEN      8
419 #define OFFSET_SPACE    2
420 #define HEX_START       (OFFSET_START + OFFSET_LEN + OFFSET_SPACE)
421 #define HEX_LEN         (BYTES_PER_LINE * 3)    /* extra space at column 8 */
422 #define HEX_SPACE       2
423 #define ASCII_START     (HEX_START + HEX_LEN + HEX_SPACE)
424 #define ASCII_LEN       (BYTES_PER_LINE + 1)    /* extra space at column 8 */
425 #define ASCII_SPACE     0
426 #define LINE_LEN        (ASCII_START + ASCII_LEN + ASCII_SPACE)
427
428 static const char       bin2hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
429                                      '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
430 static void
431 followPrintHex(
432   const char *  prefixp,
433   guint32       offset,
434   void *        datap,
435   int           len
436   )
437 {
438   int           ii;
439   int           jj;
440   int           kk;
441   guint8        val;
442   char          line[LINE_LEN + 1];
443
444   for (ii = 0, jj = 0, kk = 0; ii < len; )
445   {
446     if ((ii % BYTES_PER_LINE) == 0)
447     {
448       /* new line */
449       g_snprintf(line, LINE_LEN + 1, "%0*X", OFFSET_LEN, offset);
450       memset(line + HEX_START - OFFSET_SPACE, ' ',
451              HEX_LEN + OFFSET_SPACE + HEX_SPACE);
452
453       /* offset of hex */
454       jj = HEX_START;
455
456       /* offset of ascii */
457       kk = ASCII_START;
458     }
459
460     val = ((guint8 *)datap)[ii];
461
462     line[jj++] = bin2hex[val >> 4];
463     line[jj++] = bin2hex[val & 0xf];
464     jj++;
465
466     line[kk++] = val >= ' ' && val < 0x7f ? val : '.';
467
468     /* extra space at column 8 */
469     if (++ii % BYTES_PER_LINE == BYTES_PER_LINE/2)
470     {
471       line[jj++] = ' ';
472       line[kk++] = ' ';
473     }
474
475     if ((ii % BYTES_PER_LINE) == 0 || ii == len)
476     {
477       /* end of line or buffer */
478       if (line[kk - 1] == ' ')
479       {
480         kk--;
481       }
482       line[kk] = 0;
483       printf("%s%s\n", prefixp, line);
484       offset += BYTES_PER_LINE;
485     }
486   }
487 }
488
489 static void
490 followDraw(
491   void *        contextp
492   )
493 {
494   static const char     seperator[] =
495     "===================================================================\n";
496
497   follow_t *            fp      = (follow_t *)contextp;
498   tcp_stream_chunk      sc;
499   int                   node;
500   const address *       addr[2];
501   int                   port[2];
502   gchar                 buf[MAX_IP6_STR_LEN];
503   guint32               ii;
504   guint32               jj;
505   guint32               len;
506   guint32               chunk;
507   guint32               offset[2];
508   guint8                bin[4096];
509   char                  data[(sizeof bin * 2) + 2];
510
511   g_assert(sizeof bin % BYTES_PER_LINE == 0);
512
513   if (fp->type == type_TCP)
514   {
515     static const guint8 ip_zero[MAX_IPADDR_LEN] = {0};
516     follow_stats_t      stats;
517     address_type        type;
518
519     follow_stats(&stats);
520
521     if (stats.port[0] == 0 && stats.port[1] == 0 &&
522         memcmp(stats.ip_address[0], ip_zero, sizeof ip_zero) == 0 &&
523         memcmp(stats.ip_address[1], ip_zero, sizeof ip_zero) == 0)
524     {
525       type = AT_NONE;
526       len  = 0;
527     }
528     else if (stats.is_ipv6)
529     {
530       type = AT_IPv6;
531       len  = 16;
532     }
533     else
534     {
535       type = AT_IPv4;
536       len  = 4;
537     }
538
539     for (node = 0; node < 2; node++)
540     {
541       memcpy(fp->addrBuf[node], stats.ip_address[node], len);
542       SET_ADDRESS(&fp->addr[node], type, len, fp->addrBuf[node]);
543       fp->port[node] = stats.port[node];
544     }
545   }
546
547   /* find first stream chunk */
548   rewind(fp->filep);
549   for (chunk = 0;;)
550   {
551     len = (guint32)fread(&sc, 1, sizeof sc, fp->filep);
552     if (len != sizeof sc)
553     {
554       /* no data */
555       sc.dlen = 0;
556       memcpy(sc.src_addr, fp->addr[0].data, fp->addr[0].len) ;
557       sc.src_port = fp->port[0];
558       break;
559     }
560     if (sc.dlen > 0)
561     {
562       chunk++;
563       break;
564     }
565   }
566
567   /* node 0 is source of first chunk with data */
568   if (memcmp(sc.src_addr, fp->addr[0].data, fp->addr[0].len) == 0 &&
569       sc.src_port == fp->port[0])
570   {
571     addr[0] = &fp->addr[0];
572     port[0] = fp->port[0];
573     addr[1] = &fp->addr[1];
574     port[1] = fp->port[1];
575   }
576   else
577   {
578     addr[0] = &fp->addr[1];
579     port[0] = fp->port[1];
580     addr[1] = &fp->addr[0];
581     port[1] = fp->port[0];
582   }
583
584   printf("\n%s", seperator);
585   printf("Follow: %s,%s\n", followStrType(fp), followStrMode(fp));
586   printf("Filter: %s\n", followStrFilter(fp));
587
588   for (node = 0; node < 2; node++)
589   {
590     address_to_str_buf(addr[node], buf, sizeof buf);
591     if (addr[node]->type == AT_IPv6)
592     {
593       printf("Node %u: [%s]:%d\n", node, buf, port[node]);
594     }
595     else
596     {
597       printf("Node %u: %s:%d\n", node, buf, port[node]);
598     }
599   }
600
601   offset[0] = offset[1] = 0;
602
603   while (chunk <= fp->chunkMax)
604   {
605     node = (memcmp(addr[0]->data, sc.src_addr, addr[0]->len) == 0 &&
606             port[0] == sc.src_port) ? 0 : 1;
607
608     if (chunk < fp->chunkMin)
609     {
610       while (sc.dlen > 0)
611       {
612         len = sc.dlen < sizeof bin ? sc.dlen : (guint32)sizeof bin;
613         sc.dlen -= len;
614         if (fread(bin, 1, len, fp->filep) != len)
615         {
616           followExit("Error reading stream chunk data.");
617         }
618         offset[node] += len;
619       }
620     }
621     else
622     {
623       switch (fp->mode)
624       {
625       case mode_HEX:
626         break;
627
628       case mode_ASCII:
629         printf("%s%d\n", node ? "\t" : "", sc.dlen);
630         break;
631
632       case mode_RAW:
633         if (node)
634         {
635           putchar('\t');
636         }
637         break;
638       }
639
640       while (sc.dlen > 0)
641       {
642         len = sc.dlen < sizeof bin ? sc.dlen : (guint32)sizeof bin;
643         sc.dlen -= len;
644         if (fread(bin, 1, len, fp->filep) != len)
645         {
646           followExit("Error reading stream chunk data.");
647         }
648
649         switch (fp->mode)
650         {
651         case mode_HEX:
652           followPrintHex(node ? "\t" : "", offset[node], bin, len);
653           break;
654
655         case mode_ASCII:
656           for (ii = 0; ii < len; ii++)
657           {
658             switch (bin[ii])
659             {
660             case '\r':
661             case '\n':
662               data[ii] = bin[ii];
663             break;
664             default:
665               data[ii] = isprint(bin[ii]) ? bin[ii] : '.';
666               break;
667             }
668           }
669           if (sc.dlen == 0)
670           {
671             data[ii++] = '\n';
672           }
673           data[ii] = 0;
674           printf("%s", data);
675           break;
676
677         case mode_RAW:
678           for (ii = 0, jj = 0; ii < len; ii++)
679           {
680             data[jj++] = bin2hex[bin[ii] >> 4];
681             data[jj++] = bin2hex[bin[ii] & 0xf];
682           }
683           if (sc.dlen == 0)
684           {
685             data[jj++] = '\n';
686           }
687           data[jj] = 0;
688           printf("%s", data);
689         }
690
691         offset[node] += len;
692       }
693     }
694
695     for (;;)
696     {
697       len = (guint32)fread(&sc, 1, sizeof sc, fp->filep);
698       if (len != sizeof sc)
699       {
700         /* no more data */
701         sc.dlen = 0;
702         goto done;
703       }
704       if (sc.dlen > 0)
705       {
706         chunk++;
707         break;
708       }
709     }
710   }
711
712 done:
713
714   printf("%s", seperator);
715
716   followFileClose(fp);
717 }
718
719 static gboolean
720 followArgStrncmp(
721   const char ** opt_argp,
722   const char *  strp
723   )
724 {
725   int           len     = (guint32)strlen(strp);
726
727   if (strncmp(*opt_argp, strp, len) == 0)
728   {
729     *opt_argp += len;
730     return TRUE;
731   }
732   return FALSE;
733 }
734
735 static void
736 followArgMode(
737   const char ** opt_argp,
738   follow_t *    fp
739   )
740 {
741   if (followArgStrncmp(opt_argp, STR_HEX))
742   {
743     fp->mode = mode_HEX;
744   }
745   else if (followArgStrncmp(opt_argp, STR_ASCII))
746   {
747     fp->mode = mode_ASCII;
748   }
749   else if (followArgStrncmp(opt_argp, STR_RAW))
750   {
751     fp->mode = mode_RAW;
752   }
753   else
754   {
755     followExit("Invalid display mode.");
756   }
757 }
758
759 static void
760 followArgFilter(
761   const char ** opt_argp,
762   follow_t *    fp
763   )
764 {
765 #define _STRING(s)      # s
766 #define STRING(s)       _STRING(s)
767
768 #define ADDR_CHARS      80
769 #define ADDR_LEN        (ADDR_CHARS + 1)
770 #define ADDRv6_FMT      ",[%" STRING(ADDR_CHARS) "[^]]]:%d%n"
771 #define ADDRv4_FMT      ",%" STRING(ADDR_CHARS) "[^:]:%d%n"
772
773   int           len;
774   unsigned int  ii;
775   char          addr[ADDR_LEN];
776
777   if (sscanf(*opt_argp, ",%u%n", &fp->index, &len) == 1 &&
778       ((*opt_argp)[len] == 0 || (*opt_argp)[len] == ','))
779   {
780     *opt_argp += len;
781   }
782   else
783   {
784     for (ii = 0; ii < sizeof fp->addr/sizeof *fp->addr; ii++)
785     {
786       if ((sscanf(*opt_argp, ADDRv6_FMT, addr, &fp->port[ii], &len) != 2 &&
787            sscanf(*opt_argp, ADDRv4_FMT, addr, &fp->port[ii], &len) != 2) ||
788           fp->port[ii] <= 0 || fp->port[ii] > G_MAXUINT16)
789       {
790         followExit("Invalid address:port pair.");
791       }
792
793       if (strcmp("ip6", host_ip_af(addr)) == 0)
794       {
795         if (!get_host_ipaddr6(addr, (struct e_in6_addr *)fp->addrBuf[ii]))
796         {
797           followExit("Can't get IPv6 address");
798         }
799         SET_ADDRESS(&fp->addr[ii], AT_IPv6, 16, fp->addrBuf[ii]);
800       }
801       else
802       {
803         if (!get_host_ipaddr(addr, (guint32 *)fp->addrBuf[ii]))
804         {
805           followExit("Can't get IPv4 address");
806         }
807         SET_ADDRESS(&fp->addr[ii], AT_IPv4, 4, fp->addrBuf[ii]);
808       }
809
810       *opt_argp += len;
811     }
812
813     if (fp->addr[0].type != fp->addr[1].type)
814     {
815       followExit("Mismatched IP address types.");
816     }
817     fp->index = G_MAXUINT32;
818   }
819 }
820
821 static void
822 followArgRange(
823   const char ** opt_argp,
824   follow_t *    fp
825   )
826 {
827   int           len;
828
829   if (**opt_argp == 0)
830   {
831     fp->chunkMin = 1;
832     fp->chunkMax = G_MAXUINT32;
833   }
834   else
835   {
836     if (sscanf(*opt_argp, ",%u-%u%n",  &fp->chunkMin, &fp->chunkMax, &len) == 2)
837     {
838       *opt_argp += len;
839     }
840     else if (sscanf(*opt_argp, ",%u%n", &fp->chunkMin, &len) == 1)
841     {
842       fp->chunkMax = fp->chunkMin;
843       *opt_argp += len;
844     }
845     else
846     {
847       followExit("Invalid range.");
848     }
849
850     if (fp->chunkMin < 1 || fp->chunkMin > fp->chunkMax)
851     {
852       followExit("Invalid range value.");
853     }
854   }
855 }
856
857 static void
858 followArgDone(
859   const char * opt_argp
860   )
861 {
862   if (*opt_argp != 0)
863   {
864     followExit("Invalid parameter.");
865   }
866 }
867
868 static void
869 followTcp(
870   const char *  opt_argp,
871   void *        userdata _U_
872   )
873 {
874   follow_t *    fp;
875   GString *     errp;
876
877   opt_argp += strlen(STR_FOLLOW_TCP);
878
879   fp = followAlloc(type_TCP);
880
881   followArgMode(&opt_argp, fp);
882   followArgFilter(&opt_argp, fp);
883   followArgRange(&opt_argp, fp);
884   followArgDone(opt_argp);
885
886   reset_tcp_reassembly();
887   if (fp->index != G_MAXUINT32)
888   {
889     if (!follow_tcp_index(fp->index))
890     {
891       followExit("Can't follow tcp index.");
892     }
893   }
894   else
895   {
896     if (!follow_tcp_addr(&fp->addr[0], fp->port[0],
897                          &fp->addr[1], fp->port[1]))
898     {
899       followExit("Can't follow tcp address/port pairs.");
900     }
901   }
902
903   followFileOpen(fp);
904
905   errp = register_tap_listener("frame", fp, NULL, 0,
906                                NULL, NULL, followDraw);
907   if (errp != NULL)
908   {
909     followFree(fp);
910     g_string_free(errp, TRUE);
911     followExit("Error registering tcp tap listner.");
912   }
913 }
914
915 static void
916 followUdp(
917   const char *  opt_argp,
918   void *        userdata _U_
919   )
920 {
921   follow_t *    fp;
922   GString *     errp;
923
924   opt_argp += strlen(STR_FOLLOW_UDP);
925
926   fp = followAlloc(type_UDP);
927
928   followArgMode(&opt_argp, fp);
929   followArgFilter(&opt_argp, fp);
930   followArgRange(&opt_argp, fp);
931   followArgDone(opt_argp);
932
933   if (fp->index != G_MAXUINT32)
934   {
935     followExit("UDP does not support index filters.");
936   }
937
938   followFileOpen(fp);
939
940   errp = register_tap_listener("udp_follow", fp, followStrFilter(fp), 0,
941                                NULL, followUdpPacket, followDraw);
942   if (errp != NULL)
943   {
944     followFree(fp);
945     g_string_free(errp, TRUE);
946     followExit("Error registering udp tap listner.");
947   }
948 }
949
950 static void
951 followSsl(
952   const char *  opt_argp,
953   void *        userdata _U_
954   )
955 {
956   follow_t *    fp;
957   GString *     errp;
958
959   opt_argp += strlen(STR_FOLLOW_SSL);
960
961   fp = followAlloc(type_SSL);
962
963   followArgMode(&opt_argp, fp);
964   followArgFilter(&opt_argp, fp);
965   followArgRange(&opt_argp, fp);
966   followArgDone(opt_argp);
967
968   if (fp->index == G_MAXUINT32)
969   {
970     followExit("SSL only supports index filters.");
971   }
972
973   followFileOpen(fp);
974
975   errp = register_tap_listener("ssl", fp, followStrFilter(fp), 0,
976                                NULL, followSslPacket, followDraw);
977   if (errp != NULL)
978   {
979     followFree(fp);
980     g_string_free(errp, TRUE);
981     followExit("Error registering ssl tap listner.");
982   }
983 }
984
985 void
986 register_tap_listener_follow(void)
987 {
988   register_stat_cmd_arg(STR_FOLLOW_TCP, followTcp, NULL);
989   register_stat_cmd_arg(STR_FOLLOW_UDP, followUdp, NULL);
990   register_stat_cmd_arg(STR_FOLLOW_SSL, followSsl, NULL);
991 }