-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stop sniff() asynchronously #989
Comments
This is actually quite easy to do, using the Obviously, this will have to wait for a new packet to be sniffed (otherwise recieving on the socket is stuck) https://github.com/secdev/scapy/blob/master/scapy/sendrecv.py#L622-L625
|
Your example works, if there is a packet. As the documentation says #!/usr/bin/env python3
import time, threading
from scapy.all import sniff
e = threading.Event()
def _sniff(e):
a = sniff(filter="tcp port 80", stop_filter=lambda p: e.is_set())
print("Stopped after %i packets" % len(a))
print("Start capturing thread")
t = threading.Thread(target=_sniff, args=(e,))
t.start()
time.sleep(3)
print("Try to shutdown capturing...")
e.set()
# This will run until you send a HTTP request somewhere
# There is no way to exit clean if no package is received
while True:
t.join(2)
if t.is_alive():
print("Thread is still running...")
else:
break
print("Shutdown complete!") |
Well we could add the I don't think they would be a proper way we could internally abort |
I will suggest that you build your own packet capture logic using Scapy SuperSocket and select, such as:
|
@guedou that looks promising. I will give it a try within the next week. Do you think its worth the effort implementing this as new feature for scapy? Passing in a threading.Event and checking for isSet() should be simple |
That way too complicated. I think that adding a callback that is triggered when select and its friends do not return file descriptors is the way to go.
|
Feel free to reopen if needed. |
The suggested custom implementation with SuperSocket worked perfectly fine, thank you! |
I just published a blog post about a way to address this issue: http://blog.skyplabs.net/2018/03/01/python-sniffing-inside-a-thread-with-scapy/ . I hope it will help you. |
Thanks!
…Sent from my iPhone
On 2 Mar 2018, at 13:12, Skyper ***@***.***> wrote:
I just published a blog post about a way to address this issue: http://blog.skyplabs.net/2018/03/01/python-sniffing-inside-a-thread-with-scapy/ . I hope it will help you.
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@SkypLabs Your post is about stop_filter. A little observation: one could also use stop_callback which is called more often. Apart from that, I wrote a custom version of sniff to address this issue optimally (using select). Feel free to use it. def sniff(store=False, prn=None, lfilter=None,
stop_event=None, refresh=.1, *args, **kwargs):
"""Sniff packets
sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args)
store: wether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned,
it is displayed. Ex:
ex: prn = lambda x: x.summary()
lfilter: python function applied to each packet to determine
if further action may be done
ex: lfilter = lambda x: x.haslayer(Padding)
stop_event: Event that stops the function when set
refresh: check stop_event.set() every refresh seconds
"""
s = conf.L2listen(type=ETH_P_ALL, *args, **kwargs)
remain = None
lst = []
try:
while True:
if stop_event and stop_event.is_set():
break
sel = select([s], [], [], refresh)
if s in sel[0]:
p = s.recv(MTU)
if p is None:
break
if lfilter and not lfilter(p):
continue
if store:
lst.append(p)
c += 1
if prn:
r = prn(p)
if r is not None:
print(r)
except KeyboardInterrupt:
pass
finally:
s.close()
return plist.PacketList(lst, "Sniffed") |
No, using
As I have already said in this issue, "using a SuperSocket with a timeout works fine but this method is resource-consuming since you have to check every X seconds if the sniffing loop should be stopped or not." |
@SkypLabs maybe I missed something, but I think your method doesn't actually quit the sniffer. It works only if you have a lot of packets. Try it with an impossible filter (like 'tcp port 12321'), and you will see it doesn't stop. My bad for I don't think one check every second is a major performance issue. The most efficient way would maybe to add a dumb pipe between threads to the select, but I don't think it is worth it (after all we code in Python so performance isn't our main concern) |
Yes it does, even when there is no traffic (even with
No worries :)
Well, I suppose we can debate about it for a long. I just prefer not to trigger a check every second :) |
Oh, I think I understand now, but I still don't agree. I think that in your solution, the event doesn't do anything if the select doesn't receive any packet (and I think you agree). So it's just nice in most cases but does not solve anything in general. I tested, and what your code does is closing a socket while select listens in a separate thread. This is in fact undefined behavior, see:
The best solution would really be to use a pipe. |
Yes, the event is just here to tell the sniffing loop to stop but won't have any effect if the
Actually, my code force-stops the sniffing loop and then closes the socket. There is no race between the two threads. |
Can it be reopened? p = None On Windows it works, because there's PcapTimeout exception raised in case of no packets, which allows the condition to be checked. What about the mentioned stop_sniff additional parameter to sniff as alternative? On Windows it would work, as indicated before, even if stop wouldn't occur immediately. I don't know about other platforms, though. What's your opinion? Regards, |
Implemented To answer the long unanswered questions:
Correct.
This makes no sense. You can't cancel a
I'll be locking this thread in a few days, as it's still the footer of a closed issue. |
Yes you're right. I just realised my mistake. I've spoken too fast. Thank you @gpotter2 for your great work on #1999 by the way. I'm glad to see a permanent solution being integrated directly into Scapy. |
Hi there,
we are using scapy to built something similar to tcpdump.
The capturing process runs in its own thread:
Basically we have a flag that is set externally from the main thread if the capturing process should stop. This works as long as a package is received after the stop flag is set. But if there is no package the thread (
recv()
) hangs until the next package is received and the callback is fired.We could built something like this by passing the
timeout
tosniff()
:But I think with this approach there might be packages that get lost between the sniffing calls, am I right?
Are there any other approaches to stop
sniff()
async without losing packages?The text was updated successfully, but these errors were encountered: