1

I'm trying to use Pyshark to capture traffic about a tcp connection, to determine metrics such as RTT, throughput, and packet loss. However, it seems these attributes are not always available.

I'm successfully capturing packets, with a TCP layer. However, when accessing the packet.tcp.analysis_ack_rtt value, sometimes a value is returned, while other times an AttributeError is thrown.

capture = pyshark.LiveCapture(interface="eno1", bpf_filter="tcp and port 5201")

for packet in capture.sniff_continuously():
    print("RTT", packet.tcp.analysis_ack_rtt)

I was sort of expecting all packets to have this field, and don't see a reason why some packets do while others don't.

On a separate note, does anyone know how to access tcp.analysis.lost_segment? It seems it is also not an attribute of the packets.

Kevin
  • 11
  • 3

3 Answers3

0

Well I see you are listening on the ethernet interface. I would say that the reason for this not working is that not all packets are not going to be tcp. Hence the error. I would consider you doing a try and catch(for attribute errors) and you should be fine.

See below:

import pyshark

capture = pyshark.FileCapture(<path to pcap file>)

for packet in capture:
    try:
        print("Protocol: "+ packet.highest_layer +"source:"+ packet.ip.src +" Destination:"+ packet.ip.dst  +" RTT:"+ packet.tcp.analysis_ack_rtt)

    except AttributeError as e:
        pass
Torch
  • 51
  • 1
  • 9
0

The problem of Dynamic Layer References is explained here:

Using the dynamic layer attributes I mentioned earlier gives us some flexibility when analyzing packets. If you try to access the pkt.dns.qry_resp attribute of every packet, you will receive an AttributeError if the packet doesn't have DNS info. This also applies to transport layer, since each packet will have either a TCP or UDP layer. We can print out the source and destination addresses and ports (for IP conversation mapping) and use a try/except loop to protect against the AttributeError if the packet is neither TCP nor UDP

Jacob
  • 410
  • 3
  • 11
0

You likely solved this problem already, but I figured that I would provide an answer anyway, because I'm interested in pyshark and its capabilities.

Hopefully, these answers are useful to you.

Example One

# Network interface used by TShark for live capture
network_interface = 'en0'

capture = pyshark.LiveCapture(interface=network_interface)
capture.sniff(timeout=50)
for raw_packet in capture.sniff_continuously():
    try:
        # Only looks at TCP packets
        if hasattr(raw_packet, 'tcp'):
           source_address = raw_packet.ip.src
           source_port = raw_packet[raw_packet.transport_layer].srcport
        
           destination_address = raw_packet.ip.dst
           destination_port = raw_packet[raw_packet.transport_layer].dstport
        
           ack_rtt = raw_packet[raw_packet.transport_layer].analysis_ack_rtt

           # analysis_lost_segment can produce multiple messages:
           #
           # (1) 'tcp previous segment not captured.
           # This message is created when TShark didn't see a packet that should have been in the trace.
           # This warning was previously called "tcp previous segment lost"
           #
           # (2) 'Previous segment not captured (common at capture start)'
           # This means that on the receiver side you capture an outgoing ACK packet 
           # for a sequence number where you haven't seen the respective segment. 
           # This is common, as it might be possible that a segment arrived, 
           # you started the capture and afterwards your TCP stack replied 
           # with an ACK. So there was no way to see the incoming packet.
           #
           lost_segment = raw_packet[raw_packet.transport_layer].analysis_lost_segment

           print(f'Source Address: {source_address}\n'
                 f'Source Port: {source_port}\n'
                 f'Destination address: {destination_address}\n'
                 f'Destination port:{destination_port}\n'
                 f'RTT to ACK was: {ack_rtt} seconds\n'
                 f'{lost_segment}\n')
           
           # PRINT OUTPUT
           Source Address: 192.168.86.35
           Source Port: 64490
           Destination address: 31.13.66.174
           Destination port:443
           RTT to ACK was: 0.000162000 seconds
           Previous segment(s) not captured (common at capture start)

     except AttributeError as e:
         pass

Example Two

# Network interface used by TShark for live capture
network_interface = 'en0'

capture = pyshark.LiveCapture(interface='en0', display_filter='tcp.analysis.ack_rtt or tcp.analysis.lost_segment')
capture.sniff(timeout=50)
for raw_packet in capture.sniff_continuously():
    try:
       
        source_address = raw_packet.ip.src
        source_port = raw_packet[raw_packet.transport_layer].srcport
        
        destination_address = raw_packet.ip.dst
        destination_port = raw_packet[raw_packet.transport_layer].dstport
        
        ack_rtt = raw_packet[raw_packet.transport_layer].analysis_ack_rtt

        # analysis_lost_segment can produce multiple messages:
        #
        # (1) 'tcp previous segment not captured.
        # This message is created when TShark didn't see a packet that should have been in the trace.
        # This warning was previously called "tcp previous segment lost"
        #
        # (2) 'Previous segment not captured (common at capture start)'
        # This means that on the receiver side you capture an outgoing ACK packet 
        # for a sequence number where you haven't seen the respective segment. 
        # This is common, as it might be possible that a segment arrived, 
        # you started the capture and afterwards your TCP stack replied 
        # with an ACK. So there was no way to see the incoming packet.
        #
        lost_segment = raw_packet[raw_packet.transport_layer].analysis_lost_segment

        print(f'Source Address: {source_address}\n'
              f'Source Port: {source_port}\n'
              f'Destination address: {destination_address}\n'
              f'Destination port: {destination_port}\n'
              f'RTT to ACK was: {ack_rtt} seconds\n'
              f'{lost_segment}\n')
           
        # PRINT OUTPUT
        Source Address: 192.168.86.35
        Source Port: 64490
        Destination address: 31.13.66.174
        Destination port: 443
        RTT to ACK was: 0.000162000 seconds
        Previous segment(s) not captured (common at capture start)

    except AttributeError as e:
        pass
Life is complex
  • 15,374
  • 5
  • 29
  • 58