From 9cb3e418e15f74393292bdc49c3c70a805bbb284 Mon Sep 17 00:00:00 2001 From: Pierre LALET <pierre.lalet@cea.fr> Date: Tue, 22 Aug 2017 20:07:51 +0200 Subject: [PATCH] Merge sndrcv() for Unix & Windows systems --- scapy/arch/windows/compatibility.py | 146 +--------------------------- scapy/sendrecv.py | 97 ++++++++++-------- 2 files changed, 57 insertions(+), 186 deletions(-) diff --git a/scapy/arch/windows/compatibility.py b/scapy/arch/windows/compatibility.py index 0b4700c0..b60a86ad 100644 --- a/scapy/arch/windows/compatibility.py +++ b/scapy/arch/windows/compatibility.py @@ -29,150 +29,6 @@ import scapy.modules.six as six WINDOWS = True -def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0): - if not isinstance(pkt, Gen): - pkt = SetGen(pkt) - - if verbose is None: - verbose = conf.verb - from scapy.sendrecv import debug - debug.recv = plist.PacketList([],"Unanswered") - debug.sent = plist.PacketList([],"Sent") - debug.match = plist.SndRcvList([]) - nbrecv=0 - ans = [] - # do it here to fix random fields, so that parent and child have the same - all_stimuli = tobesent = [p for p in pkt] - notans = len(tobesent) - - hsent={} - for i in tobesent: - h = i.hashret() - if h in hsent: - hsent[h].append(i) - else: - hsent[h] = [i] - if retry < 0: - retry = -retry - autostop=retry - else: - autostop=0 - - - while retry >= 0: - found=0 - - if timeout < 0: - timeout = None - - pid=1 - try: - if WINDOWS or pid == 0: - try: - try: - i = 0 - if verbose: - print("Begin emission:") - for p in tobesent: - pks.send(p) - i += 1 - time.sleep(inter) - if verbose: - print("Finished to send %i packets." % i) - except SystemExit: - pass - except KeyboardInterrupt: - pass - except: - log_runtime.exception("--- Error sending packets") - log_runtime.info("--- Error sending packets") - finally: - try: - sent_times = [p.sent_time for p in all_stimuli if p.sent_time] - except: - pass - if WINDOWS or pid > 0: - # Timeout starts after last packet is sent (as in Unix version) - if timeout: - stoptime = time.time()+timeout - else: - stoptime = 0 - remaintime = None - try: - try: - while True: - if stoptime: - remaintime = stoptime-time.time() - if remaintime <= 0: - break - r = pks.recv(MTU) - if r is None: - continue - ok = 0 - h = r.hashret() - if h in hsent: - hlst = hsent[h] - for i, sentpkt in enumerate(hlst): - if r.answers(sentpkt): - ans.append((sentpkt, r)) - if verbose > 1: - os.write(1, b"*") - ok = 1 - if not multi: - del hlst[i] - notans -= 1 - else: - if not hasattr(sentpkt, '_answered'): - notans -= 1 - sentpkt._answered = 1 - break - if notans == 0 and not multi: - break - if not ok: - if verbose > 1: - os.write(1, b".") - nbrecv += 1 - if conf.debug_match: - debug.recv.append(r) - except KeyboardInterrupt: - if chainCC: - raise - finally: - if WINDOWS: - for p,t in zip(all_stimuli, sent_times): - p.sent_time = t - finally: - pass - - remain = list(itertools.chain(*six.itervalues(hsent))) - if multi: - remain = [p for p in remain if not hasattr(p, '_answered')] - - if autostop and len(remain) > 0 and len(remain) != len(tobesent): - retry = autostop - - tobesent = remain - if len(tobesent) == 0: - break - retry -= 1 - - if conf.debug_match: - debug.sent=plist.PacketList(remain[:],"Sent") - debug.match=plist.SndRcvList(ans[:]) - - #clean the ans list to delete the field _answered - if (multi): - for s,r in ans: - if hasattr(s, '_answered'): - del(s._answered) - - if verbose: - print("\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans)) - return plist.SndRcvList(ans),plist.PacketList(remain,"Unanswered") - - -import scapy.sendrecv as sendrecv -sendrecv.sndrcv = sndrcv def sniff(count=0, store=1, offline=None, prn = None, stop_filter=None, lfilter=None, L2socket=None, timeout=None, *arg, **karg): """Sniff packets @@ -241,7 +97,7 @@ stop_filter: python function applied to each packet to determine return plist.PacketList(lst,"Sniffed") import scapy.sendrecv -sendrecv.sniff = sniff +scapy.sendrecv.sniff = sniff # If wpcap.dll is not available if not (conf.use_winpcapy or conf.use_pcap or conf.use_dnet): diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py index b404f88f..806431ad 100644 --- a/scapy/sendrecv.py +++ b/scapy/sendrecv.py @@ -14,7 +14,7 @@ import os, sys, time, subprocess import itertools from select import select, error as select_error -from scapy.consts import DARWIN, FREEBSD, OPENBSD +from scapy.consts import DARWIN, FREEBSD, OPENBSD, WINDOWS from scapy.data import * from scapy.config import conf from scapy.packet import Gen @@ -64,34 +64,34 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 hsent={} for i in tobesent: h = i.hashret() - if h in hsent: - hsent[h].append(i) - else: - hsent[h] = [i] + hsent.setdefault(i.hashret(), []).append(i) + if retry < 0: retry = -retry - autostop=retry + autostop = retry else: - autostop=0 - + autostop = 0 while retry >= 0: - found=0 - + found = 0 + if timeout < 0: timeout = None - - rdpipe,wrpipe = os.pipe() - rdpipe=os.fdopen(rdpipe) - wrpipe=os.fdopen(wrpipe,"w") - pid=1 + if not WINDOWS: + rdpipe, wrpipe = os.pipe() + rdpipe = os.fdopen(rdpipe) + wrpipe = os.fdopen(wrpipe,"w") + + pid = None try: - pid = os.fork() - if pid == 0: + if not WINDOWS: + pid = os.fork() + if WINDOWS or pid == 0: try: - sys.stdin.close() - rdpipe.close() + if not WINDOWS: + sys.stdin.close() + rdpipe.close() try: i = 0 if verbose: @@ -107,23 +107,33 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 except KeyboardInterrupt: pass except: - log_runtime.exception("--- Error in child %i" % os.getpid()) - log_runtime.info("--- Error in child %i" % os.getpid()) + if WINDOWS: + log_runtime.exception("--- Error sending packets") + log_runtime.info("--- Error sending packets") + else: + log_runtime.exception("--- Error in child " + "%i" % os.getpid()) + log_runtime.info("--- Error in child " + "%i" % os.getpid()) finally: try: - os.setpgrp() # Chance process group to avoid ctrl-C sent_times = [p.sent_time for p in all_stimuli if p.sent_time] - six.moves.cPickle.dump( (conf.netcache,sent_times), wrpipe ) - wrpipe.close() + if not WINDOWS: + # Change process group to avoid ctrl-C + os.setpgrp() + six.moves.cPickle.dump((conf.netcache, sent_times), + wrpipe) + wrpipe.close() except: pass - elif pid < 0: + elif not WINDOWS and pid < 0: log_runtime.error("fork error") - else: - wrpipe.close() + elif WINDOWS or pid > 0: + if not WINDOWS: + wrpipe.close() + inmask = [rdpipe, pks] stoptime = 0 remaintime = None - inmask = [rdpipe,pks] try: try: while True: @@ -132,19 +142,21 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 if remaintime <= 0: break r = None - if conf.use_bpf: + if WINDOWS: + r = pks.recv(MTU) + elif conf.use_bpf: from scapy.arch.bpf.supersocket import bpf_select inp = bpf_select(inmask) if pks in inp: r = pks.recv() elif not isinstance(pks, StreamSocket) and (FREEBSD or DARWIN or OPENBSD): - inp, out, err = select(inmask,[],[], 0.05) + inp, _, _ = select(inmask, [], [], 0.05) if len(inp) == 0 or pks in inp: r = pks.nonblock_recv() else: inp = [] try: - inp, out, err = select(inmask,[],[], remaintime) + inp, _, _ = select(inmask, [], [], remaintime) except (IOError, select_error) as exc: # select.error has no .errno attribute if exc.args[0] != errno.EINTR: @@ -153,9 +165,9 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 break if pks in inp: r = pks.recv(MTU) - if rdpipe in inp: + if WINDOWS and rdpipe in inp: if timeout: - stoptime = time.time()+timeout + stoptime = time.time() + timeout del(inmask[inmask.index(rdpipe)]) if r is None: continue @@ -189,13 +201,16 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 if chainCC: raise finally: - try: - nc,sent_times = six.moves.cPickle.load(rdpipe) - except EOFError: - warning("Child died unexpectedly. Packets may have not been sent %i"%os.getpid()) + if not WINDOWS: + try: + nc, sent_times = six.moves.cPickle.load(rdpipe) + except EOFError: + warning("Child died unexpectedly. " + "Packets may have not been sent.") else: - conf.netcache.update(nc) - for p,t in zip(all_stimuli, sent_times): + if not WINDOWS: + conf.netcache.update(nc) + for p, t in zip(all_stimuli, sent_times): p.sent_time = t os.waitpid(pid,0) finally: @@ -213,7 +228,7 @@ 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") debug.match=plist.SndRcvList(ans[:]) @@ -223,7 +238,7 @@ def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0 for s,r in ans: if hasattr(s, '_answered'): del(s._answered) - + if verbose: print("\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans)) return plist.SndRcvList(ans),plist.PacketList(remain,"Unanswered") -- GitLab