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
Merge sndrcv() and sniff() implementations for Unix & Windows systems #770
Conversation
@gpotter2 could you have a look at this one? If it works, I'll continue this work with |
|
@gpotter2 I was talking of the other builds, this one if failing for a good reason indeed! |
b07efa8
to
41b06f2
Compare
@p-l- Oh right, I'm checking that... |
Tests are stuck on
Checking why... |
scapy/sendrecv.py
Outdated
pid=1 | ||
rdpipe, wrpipe = os.pipe() | ||
rdpipe = os.fdopen(rdpipe) | ||
wrpipe = os.fdopen(wrpipe,"w") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For multiprocessing, you may use
multiprocessing.Pipe(False)
(uni-directional) to get Connection
objects.
You can select those or, on windows, use the poll
function to replace the current pipes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!
8fa13ee
to
87374a8
Compare
@gpotter2 I've finally used threads rather than processes, it's much easier and it's better for this kind of operations. Can you by any chance have a look at why it fails under Windows (the error log is not helping me...)? Just getting this code, running |
Codecov Report
@@ Coverage Diff @@
## master #770 +/- ##
==========================================
+ Coverage 80.29% 80.41% +0.12%
==========================================
Files 138 137 -1
Lines 34088 33896 -192
==========================================
- Hits 27370 27257 -113
+ Misses 6718 6639 -79
|
It seems that you should restore the appveyor file as it was before :/ Everything seems to be working fine :) great job ! |
1f82413
to
dfaf10f
Compare
@gpotter2 I have removed the commit, and it still fails without any message... Could you also try with |
dfaf10f
to
fdb6cfc
Compare
Current appveyor tests are very glitchy :/ |
On my setup (nothing to do with Windows : Python 2.7.13 on ArchLinux), the tests fail, but pass when I remove the Main.py tests (hence this test commit). |
Those tests will be removed anyway with the new IPython console implementation, so if they break anything it's fine to remove them. |
@gpotter2 unfortunately that's something else. I guess I'll have to get a Windows VM with Python + Scapy... Can you confirm that this code seems to work on your setup? Thanks! |
0188ec2
to
952bbf2
Compare
I'm going to try to debug this. |
scapy/arch/pcapdnet.py
Outdated
del(self.ins) | ||
if hasattr(self, "outs"): | ||
del(self.outs) | ||
if self.closed: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?! Dont you mean not self.closed
? Same above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indeed!
scapy/sendrecv.py
Outdated
elif conf.use_pcap: | ||
r = pks.nonblock_recv() | ||
elif not isinstance(pks, StreamSocket) and ( | ||
FREEBSD or DARWIN or OPENBSD or WINDOWS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The or WINDOWS
will never be triggered here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally. This is probably not the reason why the tests fail, but still. Thanks!
952bbf2
to
53ecfb7
Compare
@gpotter2 changes from your remarks have been applied. |
I think I have found the bug. Winpcap cannot support multi-threaded different actions on the same socket objects: it's not possible to recieve and send packets at the same time on the same socket (
Several options:
|
What is a exactly in your code? Can you report the output of |
Sorry, updated my code for
I tried with your branch and upstream/master. Same result |
8ddab19
to
d852e77
Compare
scapy/sendrecv.py
Outdated
@@ -44,12 +47,41 @@ class debug: | |||
#################### | |||
|
|||
|
|||
def _sndrcv_snd(pks, timeout, inter, verbose, tobesent, all_stimuli, stopevent): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a doctring here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. I would really that you move the _select() and _get_pkt() definitions in a dedicated function.
scapy/sendrecv.py
Outdated
except KeyboardInterrupt: | ||
pass | ||
except: | ||
log_runtime.exception("--- Error sending packets") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be nicer with:
msg = "--- Error sending packets"
log_runtime.exception(msg)
log_runtime.info(msg)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally. I've used a single call, to .info()
with exc_info
instead.
|
||
autostop = 0 | ||
|
||
if WINDOWS: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we move this piece of code in a dedicated function, for example in scapy/arch ? This will make sndrcv() smaller and easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_get_pkt()
has specific implementations:
- under windows (this one)
- (but also) when using BPF
- (or) when using PCAP under Darwin, FreeBSD or OpenBSD, and the socket is not a
SuperSocket
instance.
I don't think it would make the code easier to read to move only this implementation elsewhere. Plus the last specific implementation relies on the socket type.
The important point was to move the tests outside the loops.
scapy/sendrecv.py
Outdated
@@ -213,20 +200,20 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 | |||
if len(tobesent) == 0: | |||
break | |||
retry -= 1 | |||
|
|||
if conf.debug_match: | |||
debug.sent=plist.PacketList(remain[:],"Sent") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you are at it s/,/, /
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applied.
scapy/sendrecv.py
Outdated
is displayed. | ||
Ex: prn = lambda x: x.summary() | ||
filter: BPF filter | ||
lfilter: python function applied to each packet to determine if further |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/python/Python/g as well as below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applied.
lst = [] | ||
if timeout is not None: | ||
stoptime = time.time()+timeout | ||
remain = None | ||
read_allowed_exceptions = () | ||
if conf.use_bpf: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as before, could we move this piece of code in a dedicated function ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my answer to your previous comment. Those functions use a local variable of sniff()
. We could add a second parameter, but defining an auxiliary function works well here.
d852e77
to
8d69d48
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good !
OK, I understand. I don't like function definitions inside functions.
When possible, I prefer to define them outside. Here, it might be to
cumbersome to define get_pkt() outside sndrcv()
|
@guedou the purpose of using such functions is to prevent tests from being checked inside the loop. However, to decide which function we want to use, we need information we can only have inside the function. That's why these functions are defined inside the function (but outside the loop). |
@p-l- I understood the first time. I agree, that in this case, it is not possible to do what I asked for. |
Good to be merged. @gpotter2 do you want to have another look ? |
scapy/arch/windows/compatibility.py
Outdated
|
||
import scapy.sendrecv | ||
sendrecv.sniff = sniff | ||
from scapy.config import conf | ||
|
||
# If wpcap.dll is not available | ||
if not (conf.use_winpcapy or conf.use_pcap or conf.use_dnet): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to delete compatibility.py
now, just add what's left instead of the dirty import in arch/__init__.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
scapy/sendrecv.py
Outdated
c = 0 | ||
for arg in ['opened_socket', 'offline', 'iface']: | ||
if arg in kargs: | ||
del kargs[arg] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we should print a warning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed!
scapy/sendrecv.py
Outdated
for s, label in iteritems(opened_socket)) | ||
else: | ||
sniff_sockets.update((s, "socket%d" % i) | ||
for i, s in enumerate(opened_socket)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would prefer
if isinstance(opened_socket, dict):
sniff_sockets.update((s, label)
for s, label in iteritems(opened_socket))
elif isinstance(opened_socket, list):
sniff_sockets.update((s, "socket%d" % i)
for i, s in enumerate(opened_socket))
else:
opened_socket = [opened_socket]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you have an error in your else:
block, but the idea is good indeed!
0439a92
to
e8ef4a6
Compare
This removes duplicated code and should make bridge_and_sniff() function work under Windows.
e8ef4a6
to
a9c489d
Compare
Could you leave the import to |
a9c489d
to
47bd4e2
Compare
@gpotter2 done. I think the |
I am fine with this PR. Could you merge it for me ? I am currently away form a decent keyboard.
|
This avoids duplicated code and brings to Windows enhancements that exist for Unix (
sniff()
on multiple interfaces, parallelsndrcv()
).It also brings a huge code clean-up on both functions and may have a (limited but positive) impact on performances (some tests have been moved outside of sniff loops). The code is (IMO) much more readable and maintainable.
It changes the behavior of
sniff()
: it is now possible to provide lists foroffline
andopened_socket
parameters (that was only possible foriface
). It is also possible, for those three parameters, to provide dict objects mapping an element (interface or file name, or opened socket) to a label.Also, fixes #780.