Sajan Maharjan
Sajan Maharjan

Reputation: 118

I want to stop packet capture while sniffing continuously once a condition is met

Problem

I have written a script that sniffs packet from a host, however, I am sniffing the packets in continuous mode and would like to stop sniffing on a timeout. I have written the following code to stop packet sniffing, but it doesn't seem to stop when the time has clearly exceeded the timeout. What could I be doing wrong in here?

import time
import pyshark

prog_start = time.time()
capture = pyshark.LiveCapture(interface='en0')
capture.sniff(timeout=10)
start_time = capture[0].frame_info.time_epoch
end_time = capture[-1].frame_info.time_epoch
print("Capture lasted:", float(end_time) - float(start_time))
pkt_num = 0
for pkt in capture:
    pkt_num += 1
    print("Time", time.time() - prog_start, "Pkt#", pkt_num)

We then get this output, with thousands of additional packets a second, past when the capture should have stopped:

Capture lasted: 9.148329019546509
Time 10.346031188964844 Pkt# 1
Time 10.348641157150269 Pkt# 2
Time 10.351708889007568 Pkt# 3
Time 10.353564977645874 Pkt# 4
Time 10.35555100440979 Pkt# 5
...

Question

Why does PyShark continue to capture packets after the timeout?

Upvotes: 2

Views: 4935

Answers (3)

Maf
Maf

Reputation: 735

You can use the following line in bash or even in python within os.system, os.popen or even subprocess:

while IFS= read -r line; do if [[ $line =~ 'some protocol' ]]; then <SOME_ACTION>; break; fi; done < <(sudo tshark)

Upvotes: 1

Desultory
Desultory

Reputation: 153

I was having this same issue, I managed to find a bit of a solution for it. It isn't perfect but it works by telling the capture loop to stop on the next packet and sends an empty packet it will see to make it end. I made it a udp packet on a high port for my case because I use a filter that filters out most traffic so this solution worked for me

class PacketCapture(threading.Thread):
    capture = 1

    def __init__(self, interface_name):
        threading.Thread.__init__(self)
        self.interface_name = interface_name

    def stop(self):
        self.capture = 0

    def run(self):
        capture = pyshark.LiveCapture(interface=self.interface_name)
        try:
            for packet in capture.sniff_continuously():
                if not self.capture:
                    capture.close()
        except pyshark.capture.capture.TSharkCrashException:
            self.exited = 1
            print("Capture has crashed")



#start capture
pcap = PacketCapture(interface_name)
pcap.start()

#stop capture
pcap.stop()
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
msg = bytes("", "UTF-8")
sock.sendto(msg, ("external IP", 12345))
sock.close

I'm relatively new to python myself but I think this should be a somewhat acceptable solution given the scenario

Upvotes: 2

Ross Jacobs
Ross Jacobs

Reputation: 3186

Problems with PyShark

It looks like you're running into a known issue with PyShark that hasn't been fixed in years. Per the thread, the author wrote

You can subclass LiveCapture and override the get_parameters() function, adding your own parameters.

You could modify the parameters sent to tshark, but at this point, why not just use a tshark command directly?

Using Tshark Instead

PyShark is just a wrapper for tshark on your system. If you want to use subprocess with Python, the equivalent tshark command is tshark -a duration:5. The other advantage of using tshark directly is that subprocess gives you a pid that you can kill on an arbitrary condition.

See the manpage for more details.

Upvotes: 1

Related Questions