diff --git a/scapy/arch/windows/compatibility.py b/scapy/arch/windows/compatibility.py index b60a86ad806fb5362daf55ec549646c07780afca..5038b8e95865d3d8ac1c18aaedaa1d884acec062 100644 --- a/scapy/arch/windows/compatibility.py +++ b/scapy/arch/windows/compatibility.py @@ -7,97 +7,9 @@ Instanciate part of the customizations needed to support Microsoft Windows. """ -from __future__ import absolute_import -from __future__ import print_function -import itertools -import os -import re -import socket -import subprocess -import sys -import time +from __future__ import absolute_import, print_function -from scapy.consts import LOOPBACK_NAME -from scapy.config import conf,ConfClass -from scapy.base_classes import Gen, SetGen -import scapy.plist as plist -from scapy.utils import PcapReader, tcpdump -from scapy.arch.pcapdnet import PcapTimeoutElapsed -from scapy.error import log_runtime -from scapy.data import MTU, ETH_P_ARP,ETH_P_ALL -import scapy.modules.six as six - -WINDOWS = True - - -def sniff(count=0, store=1, offline=None, prn = None, stop_filter=None, lfilter=None, L2socket=None, timeout=None, *arg, **karg): - """Sniff packets -sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets -Select interface to sniff by setting conf.iface. Use show_interfaces() to see interface names. - count: number of packets to capture. 0 means infinity - store: whether 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() - filter: provide a BPF filter -lfilter: python function applied to each packet to determine - if further action may be done - ex: lfilter = lambda x: x.haslayer(Padding) -offline: pcap file to read packets from, instead of sniffing them -timeout: stop sniffing after a given time (default: None) -L2socket: use the provided L2socket -stop_filter: python function applied to each packet to determine - if we have to stop the capture after this packet - ex: stop_filter = lambda x: x.haslayer(TCP) - """ - c = 0 - - if offline is None: - log_runtime.info('Sniffing on %s' % conf.iface) - if L2socket is None: - L2socket = conf.L2listen - s = L2socket(type=ETH_P_ALL, *arg, **karg) - else: - flt = karg.get('filter') - s = PcapReader(offline if flt is None else - tcpdump(offline, args=["-w", "-", flt], getfd=True)) - lst = [] - if timeout is not None: - stoptime = time.time()+timeout - remain = None - while True: - try: - if timeout is not None: - remain = stoptime-time.time() - if remain <= 0: - break - - try: - p = s.recv(MTU) - except PcapTimeoutElapsed: - continue - 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) - if stop_filter and stop_filter(p): - break - if 0 < count <= c: - break - except KeyboardInterrupt: - break - s.close() - return plist.PacketList(lst,"Sniffed") - -import scapy.sendrecv -scapy.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): diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py index 96847f3754269d2decf6254746a0186004035e98..04dd3976516b72d082357658f1009fb2f5ff143f 100644 --- a/scapy/sendrecv.py +++ b/scapy/sendrecv.py @@ -27,6 +27,7 @@ from scapy.base_classes import SetGen from scapy.supersocket import StreamSocket import scapy.modules.six as six from scapy.modules.six.moves import map +from scapy.modules.six import iteritems if conf.route is None: # unused import, only to initialize conf.route import scapy.route @@ -561,94 +562,155 @@ iface: listen answers only on the given interface""" @conf.commands.register -def sniff(count=0, store=1, offline=None, prn=None, lfilter=None, +def sniff(count=0, store=True, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, iface=None, *arg, **karg): """Sniff packets sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets - count: number of packets to capture. 0 means infinity - store: whether 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() - filter: provide a BPF filter -lfilter: python function applied to each packet to determine - if further action may be done - ex: lfilter = lambda x: x.haslayer(Padding) -offline: pcap file to read packets from, instead of sniffing them -timeout: stop sniffing after a given time (default: None) -L2socket: use the provided L2socket -opened_socket: provide an object ready to use .recv() on -stop_filter: python function applied to each packet to determine - if we have to stop the capture after this packet - ex: stop_filter = lambda x: x.haslayer(TCP) -iface: interface or list of interfaces (default: None for sniffing on all -interfaces) +count: number of packets to capture. 0 means infinity +store: whether to store sniffed packets or discard them +prn: function to apply to each packet. If something is returned, it + is displayed. + Ex: prn = lambda x: x.summary() +filter: BPF filter +lfilter: python function applied to each packet to determine if further + action may be done + Ex: lfilter = lambda x: x.haslayer(Padding) +offline: pcap file (or list of pcap files) to read packets from, instead + of sniffing them +timeout: stop sniffing after a given time (default: None) +L2socket: use the provided L2socket (default: use conf.L2listen) +opened_socket: provide an object (or a list of objects) ready to use .recv() on +stop_filter: python function applied to each packet to determine if we have + to stop the capture after this packet. + Ex: stop_filter = lambda x: x.haslayer(TCP) +iface: interface or list of interfaces (default: None for sniffing on + all interfaces) + +The iface, offline and opened_socket parameters can be either an +element, a list of elements, or a dict object mapping an element to a +label (see examples below) + +Examples: + + >>> sniff(filter="arp") + + >>> sniff(lfilter=lambda pkt: ARP in pkt) + + >>> sniff(iface="eth0", prn=Packet.summary) + + >>> sniff(iface=["eth0", "mon0"], + ... prn=lambda pkt: "%s: %s" % (pkt.sniffed_on, pkt.summary())) + + >>> sniff(iface={"eth0": "Ethernet", "mon0": "Wifi"}, + ... prn=lambda pkt: "%s: %s" % (pkt.sniffed_on, pkt.summary())) + """ + if conf.use_bpf: + from scapy.arch.bpf.supersocket import bpf_select c = 0 - label = {} - sniff_sockets = [] + sniff_sockets = {} # socket: label dict if opened_socket is not None: - sniff_sockets = [opened_socket] - else: - if offline is None: - if L2socket is None: - L2socket = conf.L2listen - if isinstance(iface, list): - for i in iface: - s = L2socket(type=ETH_P_ALL, iface=i, *arg, **karg) - label[s] = i - sniff_sockets.append(s) - else: - sniff_sockets = [L2socket(type=ETH_P_ALL, iface=iface, *arg, - **karg)] + if isinstance(opened_socket, list): + sniff_sockets.update((s, "socket%d" % i) + for i, s in enumerate(opened_socket)) + elif isinstance(opened_socket, dict): + sniff_sockets.update((s, label) + for s, label in iteritems(opened_socket)) + else: + sniff_sockets[opened_socket] = "socket0" + if offline is not None: + flt = karg.get('filter') + if isinstance(offline, list): + sniff_sockets.update((PcapReader( + fname if flt is None else + tcpdump(fname, args=["-w", "-", flt], getfd=True) + ), fname) for fname in offline) + elif isinstance(offline, dict): + sniff_sockets.update((PcapReader( + fname if flt is None else + tcpdump(fname, args=["-w", "-", flt], getfd=True) + ), label) for fname, label in iteritems(offline)) else: - flt = karg.get('filter') - sniff_sockets = [PcapReader( + sniff_sockets[PcapReader( offline if flt is None else tcpdump(offline, args=["-w", "-", flt], getfd=True) - )] + )] = offline + if not sniff_sockets or iface is not None: + if L2socket is None: + L2socket = conf.L2listen + if isinstance(iface, list): + sniff_sockets.update( + (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), ifname) + for ifname in iface + ) + elif isinstance(iface, dict): + sniff_sockets.update( + (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), iflabel) + for ifname, iflabel in iteritems(iface) + ) + else: + sniff_sockets[L2socket(type=ETH_P_ALL, iface=iface, + *arg, **karg)] = iface lst = [] if timeout is not None: stoptime = time.time()+timeout remain = None + read_allowed_exceptions = () + if conf.use_bpf: + def _select(sockets): + return bpf_select(sockets, remain) + elif WINDOWS: + from scapy.arch.pcapdnet import PcapTimeoutElapsed + read_allowed_exceptions = (PcapTimeoutElapsed,) + def _select(sockets): + try: + return sockets + except PcapTimeoutElapsed: + return [] + else: + def _select(sockets): + try: + return select(sockets, [], [], remain)[0] + except select_error as exc: + # Catch 'Interrupted system call' errors + if exc[0] == errno.EINTR: + return [] + raise try: stop_event = False - while not stop_event: + while sniff_sockets: if timeout is not None: remain = stoptime-time.time() if remain <= 0: break - if conf.use_bpf: - from scapy.arch.bpf.supersocket import bpf_select - ins = bpf_select(sniff_sockets, remain) - else: - ins, _, _ = select(sniff_sockets, [], [], remain) + ins = _select(sniff_sockets) for s in ins: - p = s.recv() - if p is None and offline is not None: - stop_event = True + try: + p = s.recv() + except read_allowed_exceptions: + continue + if p is None: + del sniff_sockets[s] + break + if lfilter and not lfilter(p): + continue + p.sniffed_on = sniff_sockets[s] + if store: + lst.append(p) + c += 1 + if prn: + r = prn(p) + if r is not None: + print(r) + if stop_filter and stop_filter(p): + sniff_sockets = [] + break + if 0 < count <= c: + sniff_sockets = [] break - elif p is not None: - if lfilter and not lfilter(p): - continue - if s in label: - p.sniffed_on = label[s] - if store: - lst.append(p) - c += 1 - if prn: - r = prn(p) - if r is not None: - print(r) - if stop_filter and stop_filter(p): - stop_event = True - break - if 0 < count <= c: - stop_event = True - break except KeyboardInterrupt: pass if opened_socket is None: