Wireshark-dev: [Wireshark-dev] Wireshark multiview feature demo
From: Mikael Wikström <[email protected]>
Date: Thu, 17 May 2012 11:56:20 +0200
Hi,

first of all I thank you all for a great piece of software.

I'd like to suggest a feature that would make wireshark even more
useful, so I thought I would describe it and see if any one else would
find it interesting.

The basic concept is to be able to view a pcap file in multiple
windows and have them track each other. Or more accurately have one
track the second one. If I then used display filters in window1 and
select a packet, window2 will move to that same packet and by doing so
one can easily see the packets close to it. I find this feature very
useful when debugging 802.11 traffic as I often want to check ACK
frames and timing related to beacons frames, if there are
retransmissions and such.

So I made a demo of the feature just to show how it would work. I
wrote this code as a demo only so no need to point out all the
security flaws it has and how it will impact performance.

I would be very interested in starting a discussion around this to see
in what way it could be improved.

I also made a very short screen cast of the demo that perhaps makes it
easier to understand what I'm talking about. You can find it here

http://www.youtube.com/watch?v=uYyELO8tdto

What I did was to make it so that window1 listens on a port and can be
controlled from a CLI interface on that port. The only implemented
command so far is "goto 2" meaning goto frame number 2. Window2 will
then send commands to window1 using that port and tell it to move to
the same frame.

demo code is in attachment.

My experience with GTK is very limited so my choice of using pthreads
was simply because it got the job done. Perhaps someone could suggest
a better way of hoking in a CLI/socket interface to wireshark?

BR,
Mikael Wikstrom
Sweden
#undef     ntohs

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static int is_cli_master = 0;
static int is_cli_slave = 0;
static int cli_port = 1100;

void jump_to_frame(unsigned int num);

int cli_build_sock(struct sockaddr_in *stSockAddr)
{
   int s;

   memset(stSockAddr, 0, sizeof(*stSockAddr));
   stSockAddr->sin_family = AF_INET;
   stSockAddr->sin_port = htons(cli_port);
#if 0
   stSockAddr.sin_addr.s_addr = INADDR_ANY;
#else
   s = inet_pton(AF_INET, "127.0.0.1", &stSockAddr->sin_addr);

   if (0 > s)
   {
      perror("error: first parameter is not a valid address family");
      return __LINE__;
   } else if (0 == s) {
      perror("char string (second parameter does not contain valid ipaddress)");
      return __LINE__;
   }
#endif
   return 0;
}

static int is_server(int SocketFD, struct sockaddr_in stSockAddr)
{
   if(-1 == bind(SocketFD,(struct sockaddr *)&stSockAddr, sizeof(stSockAddr)))
   {
      perror("error bind failed");
      return 0;
   }

   if(-1 == listen(SocketFD, 10))
   {
      perror("error listen failed");
      return 0;
   }

   return 1;
}

void tell_slave(int row)
{
   struct sockaddr_in stSockAddr;
   int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
   int s;
   char buf[64];

   if(is_cli_master)
      return;

   printf("%s %d\n", __func__, row);

   if(-1 == SocketFD)
   {
      perror("can not create socket");
      return;
   }

   s = cli_build_sock(&stSockAddr);
   if (s != 0)
   {
      close(SocketFD);
      exit(EXIT_FAILURE);
   }

   if(is_cli_slave == 0)
   {
      if(is_server(SocketFD, stSockAddr))
      {
         printf("we are able to open the listen port so this must be the master, do nothing\n");
         close(SocketFD);
         return;
      }
      printf("unable to open listen port so this must be the slave\n");
      is_cli_slave = 1;
   }

   if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr)))
   {
      perror("connect failed");
      close(SocketFD);
      //exit(EXIT_FAILURE);
      return;
   }

   s = snprintf(buf,sizeof(buf), "goto %u", row);
   s = write(SocketFD, buf, 1+s);

   shutdown(SocketFD, SHUT_RDWR);
   close(SocketFD);
}

int cli_listen(void)
{
   struct sockaddr_in stSockAddr;
   int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
   int s;

   if(-1 == SocketFD)
   {
      perror("can not create socket");
      exit(EXIT_FAILURE);
   }

   s = cli_build_sock(&stSockAddr);
   if (s != 0)
   {
      close(SocketFD);
      exit(EXIT_FAILURE);
   }

   if(-1 == bind(SocketFD,(struct sockaddr *)&stSockAddr, sizeof(stSockAddr)))
   {
      perror("error bind failed");
      close(SocketFD);
      //exit(EXIT_FAILURE);
      // may be the master so stop here
      return 0;
   }

   if(-1 == listen(SocketFD, 10))
   {
      perror("error listen failed");
      close(SocketFD);
      //exit(EXIT_FAILURE);
      // may be the master so stop here
      //exit(EXIT_FAILURE);
      return 0;
   }

   is_cli_master = 1;

   printf("slave listening for commands on port %u\n", cli_port);

   for(;;)
   {
      int ConnectFD = accept(SocketFD, NULL, NULL);
      int num;
      int r;
      int s;
      char buf[128];

      if(0 > ConnectFD)
      {
         perror("error accept failed");
         close(SocketFD);
         exit(EXIT_FAILURE);
      }

      r = read(ConnectFD,buf,sizeof(buf));
      if(r > 0 && 0 < sizeof(buf) &&
            strnlen(buf, sizeof(buf)) < sizeof(buf))
      {
         s = sscanf(buf, "goto %u", &num);
         if(s == 1)
         {
            printf("[%s] => %u\n", buf, num);
            jump_to_frame(num);
         } else {
            printf("unable to parse %d %d [%s]\n",r, s, buf);
         }
      }

      shutdown(ConnectFD, SHUT_RDWR);
      close(ConnectFD);
   }
   return EXIT_SUCCESS;
}

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define NUM_THREADS     1

#include <time.h>

void *TaskCode(void *argument)
{
   int tid = *((int *) argument);
   printf("listen on socket in separate thread %u!\n", tid);
   cli_listen();
   printf("thread is terminating %d!\n", tid);
   return NULL;
}

void cli_task_start(void)
{
   pthread_t threads[NUM_THREADS];
   int thread_args[NUM_THREADS];
   int rc, i;

   /* create all threads */
   for (i=0; i<NUM_THREADS; ++i) {
      thread_args[i] = i;
      //printf("In main: creating thread %d\n", i);
      rc = pthread_create(&threads[i], NULL, TaskCode, (void *) &thread_args[i]);
      assert(0 == rc);
   }
}

Attachment: wireshark-multiview.diff
Description: Binary data