Sunday, 5 March 2017

Programmatic Analysis of Wireshark Log Files using C#

The other day, I wanted to perform some Wireshark filtering on a .pcap file to obtain a count of the packets found for a large number of IP addresses.

I wanted to find out the number of tcp retransmissions for a specified IP address, as well as the count of TCP resets for each IP address. And finally, I wanted to get a count of the number of "keep alive" packets for each IP address.

Okay, so this is pretty easy to perform in Wireshark. Just filter the traffic with the following filters:

tcp.analysis.retransmission && ip.addr == 1.2.3.4
tcp.flags.reset == 1 && ip.addr == 1.2.3.4
tcp.analysis.keep_alive && ip.addr == 1.2.3.4  

But I didn't want to go through the user interface for hundreds of different IP addresses. I wanted to do this programatically, in code.

Now, there are a couple of different approaches you can take here depending on your requirements.

At first I used PcapDotNet. This is a great library and you can walk the packets in the file and explore the individual properties of a packet.

Simply download the binaries from here. Then reference them in your project and you're off!

The code to get up and running is simple. The code below uses the function IncomingPacketHandler to walk every packet in the .pcap file:

class Program
{
   static int m_packetNumber = 0;
     
   static void Main(string[] args)
   {
      string file = @"C:\WireSharkAnalysis\capture2.pcap";
      // Create the offline device
      OfflinePacketDevice selectedDevice = new OfflinePacketDevice(file);
         
      // 65536 guarantees that the whole packet will be captured on all the link layers
      int readWholePacket = 65536;
      
      // read timeout
      int readTimeOut = 1000;
     
      using ( PacketCommunicator communicator = selectedDevice.Open( readWholePacket, PacketDeviceOpenAttributes.Promiscuous, readTimeOut))
      {
         communicator.ReceivePackets(0, IncommingPacketHandler);
      }
   }

    private static void IncommingPacketHandler(Packet packet)
    {
        // This function will get called for every packet in the .pcap file!
        m_packetNumber++;

        Console.WriteLine( packet.Timestamp.ToString( "yyyy-MM-dd hh:mm:ss.fff") + " length:" + packet.Length);

        var testIP = new IpV4Address("10.1.1.1");

        if (packet.Ethernet.IpV4.Tcp.IsReset == true )
        {
            // do something  
        }

        if (packet.Ethernet.IpV4.Tcp.ControlBits.HasFlag( PcapDotNet.Packets.Transport.TcpControlBits.Acknowledgment) == true &&
            packet.Ethernet.IpV4.Tcp.ControlBits.HasFlag( PcapDotNet.Packets.Transport.TcpControlBits.Push) == true )
        {
            // do something       
        }

        if (packet.Ethernet.IpV4.Tcp.IsReset == false)
        {
            // do something  
        }

        if (packet.Ethernet.IpV4.Source == testIP)
        {
            // do something  
        }

        Console.WriteLine();
    }
}

You can perform deep inspection of the packet as seen below in the "quick watch" window. In short, you get access to everything.

Very neat!

But here's the thing - I wanted to get a count of the number of tcp retransmissions. That information is not available as part of each individual packet. Apparently Wireshark "compares the sequence numbers to what it has determined to be the next expected sequence number" to allow you to filter them.

This is easy in Wireshark. Just type "tcp.analysis.retransmission" into the filter bar and it will display the TCP Retransmissions. The filter is part of the TCP analysis that Wireshark performs when reading the packets.

So, that's when I turned to my second option: Using tshark.exe (the command line version of Wireshark) to read in a file and pass my filter to. I wrapped the tshark command line tool in a simple class, but the main work-horse is this function here:

public int ProcessFilter(string filter)
{
    // Stage 1: Setup the wireshark filter command
    m_tsharkCmd = string.Format(m_tsharkTemplate, m_tsharkPath, m_pcapFile, filter);

    // Stage 2: Clear the output
    m_tsharkOutput.Clear();

    // Stage 3: Run the command!
    using (m_process = new Process())
    {
        m_process.StartInfo.WorkingDirectory = @"C:\";
        m_process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
        m_process.StartInfo.UseShellExecute = false;
        m_process.StartInfo.RedirectStandardInput = true;
        m_process.StartInfo.RedirectStandardOutput = true;
        m_process.StartInfo.RedirectStandardError = true;
        m_process.OutputDataReceived += OutputHandler;
        m_process.ErrorDataReceived += OutputHandler;
        m_process.Exited += new EventHandler(process_Exited);
        m_process.Start();
        m_process.BeginOutputReadLine();
        m_process.BeginErrorReadLine();

        // Send a directory command and an exit command to the shell
        m_process.StandardInput.WriteLine(m_tsharkCmd);
        m_process.StandardInput.WriteLine("exit");
        m_process.WaitForExit();
        m_process.Close();               
    }

    // Stage 4: Output the number of packets!
    int packetCount = GetPacketCount();
    return packetCount;
}

It's a quick and dirty approach but hey, it works!

Using this approach, means I can loop around on a number of different IP addresses and issue the previous Wireshark filters I had above to find the number of tcp packet retransmissions.

tcp.analysis.retransmission && ip.addr == 1.2.3.4
tcp.flags.reset == 1 && ip.addr == 1.2.3.4
tcp.analysis.keep_alive && ip.addr == 1.2.3.4  

This small project can be found on my GitHub pages here. It's a simple stub project but can easily be expanded to perform different types analysis on any .pcap file.


Contact Me:  ocean.airdrop@gmail.com

Popular Posts

Recent Posts

Unordered List

Text Widget

Pages