Python and PyShark Network Packet Analysis

PyShark is a third-party Python module that acts as a wrapper for Tshark, a command line tool for both capturing network packets, as well as reading existing packet capture files. Tshark comes bundled with Wireshark, which provides all the functionality of Tshark and more, through a graphical user interface.

As PyShark is a third-party module, that doesn't come bundled with the standard Python library, it needs to be installed using Pip.

pip install pyshark

Due to PyShark being a wrapper for Tshark, it actually needs Tshark to be installed, which, as previously mentioned comes bundled with Wireshark, or can be installed on its own.

Below is an example of how to capture packets on a specified interface until the capture is interrupted by pressing 'Ctrl+c', or the equivalent on other platforms. The capture is saved to a file called 'key-stop.pcap' and the number of packets captured are displayed once it has been stopped.

import pyshark

try:

    # Set up the packet capture.
    capture = pyshark.LiveCapture(interface="WiFi", 
                                  output_file="c:\\demo\\key-stop.pcap")

    # Start the packet capture.
    capture.sniff()

# Stop packet capture with Ctrl+c.
except KeyboardInterrupt:

    # Display the number of packets captured.
    print(f"Packets captured: {capture}.")

As an alternative to leaving it up to user intervention to stop the packet capture, a time limit can be used, which can be specified as the number of seconds from when the capture is started.

import pyshark

# Set up the packet capture.
capture = pyshark.LiveCapture(interface="WiFi", 
                                output_file="c:\\demo\\time-limit.pcap")

# Start the packet capture, specifying a time limit in seconds.
capture.sniff(timeout=10)

This next example captures a specified number of packets. The capture is set up in a similar fashion as before. This time a ‘for’ loop is used to process the packets, and display a message including the packet number that has been captured. It should be noted that due to the way PyShark interacts with Tshark, the resulting packet capture may have a small number of packets over the limit specified.

import pyshark

# Set up the packet capture.
capture = pyshark.LiveCapture(interface="WiFi", 
                                output_file="c:\\demo\\packet-limit.pcap")

# Packet counter and limit.
counter = 1
limit = 20

# Capture 20 packets.
for packet in capture.sniff_continuously(packet_count=limit):

    # Display the number of the packet captured.
    print(f"Packet {counter} of {limit} captured.")

    # Increment the counter.
    counter += 1

As well as capturing packets, it is also possible to use PyShark to read an existing capture file.

import pyshark

# Specify packet capture to read.
capture = pyshark.FileCapture('c:\\demo\\capture.pcap')

# Process the packets in the capture.
for packet in capture:

    # Display the packet details.
    print(packet)

This will display all the information for every packet in the capture. It should be noted however that if the packet capture is large, the information at the start of the capture may not be viewable if the buffer size of the terminal being used isn't large enough.

If only certain packets are of interest, such as those relating to DNS, then a display filter can be applied.

import pyshark

# Specify packet capture to read.
capture = pyshark.FileCapture('c:\\demo\\capture.pcap', display_filter='dns')

# Process the packets in the capture.
for packet in capture:

    # Display the packet details.
    print(packet)

As well as limiting the type of packets to display with a filter, the information to display for each packet can also be specified. This can be achieved through dot notation. In the below example, only protocols, source IP address and port, along with destination IP address and port are displayed.

import pyshark

# Specify packet capture to read.
capture = pyshark.FileCapture('c:\\demo\\capture.pcap')

# Packet number.
pCount = 1

# Process the packets in the capture.
for packet in capture:

    # Display selected packet details if it's a TCP packet.
    if hasattr(packet, 'tcp'):

        # Packet count: transport and highest protocols - source IP/port - destination IP/port.
        print(f"{pCount}: {packet.transport_layer} {packet.highest_layer} - " + 
              f"Src: {packet.ip.src} {packet.tcp.srcport} - " +
              f"Dst: {packet.ip.dst} {packet.tcp.dstport}")

    # Display selected packet details if it's a UDP packet.
    elif hasattr(packet, 'udp'):

        # Packet count: transport and highest protocols - source IP/port - destination IP/port.
        print(f"{pCount}: {packet.transport_layer} {packet.highest_layer} - " +
              f"Src: {packet.ip.src} {packet.udp.srcport} - " +
              f"Dst: {packet.ip.dst} {packet.udp.dstport}")

    # Increase the packet counter.
    pCount += 1