• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
5
6"""
7Functions to send and receive packets.
8"""
9
10import itertools
11from threading import Thread, Event
12import os
13import re
14import socket
15import subprocess
16import time
17import warnings
18
19from scapy.compat import plain_str
20from scapy.data import ETH_P_ALL
21from scapy.config import conf
22from scapy.error import warning
23from scapy.interfaces import (
24    network_name,
25    resolve_iface,
26    NetworkInterface,
27)
28from scapy.packet import Packet
29from scapy.pton_ntop import inet_pton
30from scapy.utils import get_temp_file, tcpdump, wrpcap, \
31    ContextManagerSubprocess, PcapReader, EDecimal
32from scapy.plist import (
33    PacketList,
34    QueryAnswer,
35    SndRcvList,
36)
37from scapy.error import log_runtime, log_interactive, Scapy_Exception
38from scapy.base_classes import Gen, SetGen
39from scapy.sessions import DefaultSession
40from scapy.supersocket import SuperSocket, IterSocket
41
42# Typing imports
43from typing import (
44    Any,
45    Callable,
46    Dict,
47    Iterator,
48    List,
49    Optional,
50    Tuple,
51    Type,
52    Union,
53    cast
54)
55from scapy.interfaces import _GlobInterfaceType
56from scapy.plist import _PacketIterable
57
58if conf.route is None:
59    # unused import, only to initialize conf.route and conf.iface*
60    import scapy.route  # noqa: F401
61
62#################
63#  Debug class  #
64#################
65
66
67class debug:
68    recv = PacketList([], "Received")
69    sent = PacketList([], "Sent")
70    match = SndRcvList([], "Matched")
71    crashed_on = None  # type: Optional[Tuple[Type[Packet], bytes]]
72
73
74####################
75#  Send / Receive  #
76####################
77
78_DOC_SNDRCV_PARAMS = """
79    :param pks: SuperSocket instance to send/receive packets
80    :param pkt: the packet to send
81    :param timeout: how much time to wait after the last packet has been sent
82    :param inter: delay between two packets during sending
83    :param verbose: set verbosity level
84    :param chainCC: if True, KeyboardInterrupts will be forwarded
85    :param retry: if positive, how many times to resend unanswered packets
86        if negative, how many times to retry when no more packets
87        are answered
88    :param multi: whether to accept multiple answers for the same stimulus
89    :param rcv_pks: if set, will be used instead of pks to receive packets.
90        packets will still be sent through pks
91    :param prebuild: pre-build the packets before starting to send them.
92        Automatically enabled when a generator is passed as the packet
93    :param _flood:
94    :param threaded: if True, packets are sent in a thread and received in another.
95        Defaults to True.
96    :param session: a flow decoder used to handle stream of packets
97    :param chainEX: if True, exceptions during send will be forwarded
98    :param stop_filter: Python function applied to each packet to determine if
99        we have to stop the capture after this packet.
100    """
101
102
103_GlobSessionType = Union[Type[DefaultSession], DefaultSession]
104
105
106class SndRcvHandler(object):
107    """
108    Util to send/receive packets, used by sr*().
109    Do not use directly.
110
111    This matches the requests and answers.
112
113    Notes::
114      - threaded: if you're planning to send/receive many packets, it's likely
115        a good idea to use threaded mode.
116      - DEVS: store the outgoing timestamp right BEFORE sending the packet
117        to avoid races that could result in negative latency. We aren't Stadia
118    """
119    def __init__(self,
120                 pks,  # type: SuperSocket
121                 pkt,  # type: _PacketIterable
122                 timeout=None,  # type: Optional[int]
123                 inter=0,  # type: int
124                 verbose=None,  # type: Optional[int]
125                 chainCC=False,  # type: bool
126                 retry=0,  # type: int
127                 multi=False,  # type: bool
128                 rcv_pks=None,  # type: Optional[SuperSocket]
129                 prebuild=False,  # type: bool
130                 _flood=None,  # type: Optional[_FloodGenerator]
131                 threaded=True,  # type: bool
132                 session=None,  # type: Optional[_GlobSessionType]
133                 chainEX=False,  # type: bool
134                 stop_filter=None  # type: Optional[Callable[[Packet], bool]]
135                 ):
136        # type: (...) -> None
137        # Instantiate all arguments
138        if verbose is None:
139            verbose = conf.verb
140        if conf.debug_match:
141            debug.recv = PacketList([], "Received")
142            debug.sent = PacketList([], "Sent")
143            debug.match = SndRcvList([], "Matched")
144        self.nbrecv = 0
145        self.ans = []  # type: List[QueryAnswer]
146        self.pks = pks
147        self.rcv_pks = rcv_pks or pks
148        self.inter = inter
149        self.verbose = verbose
150        self.chainCC = chainCC
151        self.multi = multi
152        self.timeout = timeout
153        self.session = session
154        self.chainEX = chainEX
155        self.stop_filter = stop_filter
156        self._send_done = False
157        self.notans = 0
158        self.noans = 0
159        self._flood = _flood
160        self.threaded = threaded
161        self.breakout = Event()
162        # Instantiate packet holders
163        if prebuild and not self._flood:
164            self.tobesent = list(pkt)  # type: _PacketIterable
165        else:
166            self.tobesent = pkt
167
168        if retry < 0:
169            autostop = retry = -retry
170        else:
171            autostop = 0
172
173        if timeout is not None and timeout < 0:
174            self.timeout = None
175
176        while retry >= 0:
177            self.breakout.clear()
178            self.hsent = {}  # type: Dict[bytes, List[Packet]]
179
180            if threaded or self._flood:
181                # Send packets in thread.
182                snd_thread = Thread(
183                    target=self._sndrcv_snd
184                )
185                snd_thread.daemon = True
186
187                # Start routine with callback
188                interrupted = None
189                try:
190                    self._sndrcv_rcv(snd_thread.start)
191                except KeyboardInterrupt as ex:
192                    interrupted = ex
193
194                self.breakout.set()
195
196                # Ended. Let's close gracefully
197                if self._flood:
198                    # Flood: stop send thread
199                    self._flood.stop()
200                snd_thread.join()
201
202                if interrupted and self.chainCC:
203                    raise interrupted
204            else:
205                # Send packets, then receive.
206                try:
207                    self._sndrcv_rcv(self._sndrcv_snd)
208                except KeyboardInterrupt:
209                    if self.chainCC:
210                        raise
211
212            if multi:
213                remain = [
214                    p for p in itertools.chain(*self.hsent.values())
215                    if not hasattr(p, '_answered')
216                ]
217            else:
218                remain = list(itertools.chain(*self.hsent.values()))
219
220            if autostop and len(remain) > 0 and \
221               len(remain) != len(self.tobesent):
222                retry = autostop
223
224            self.tobesent = remain
225            if len(self.tobesent) == 0:
226                break
227            retry -= 1
228
229        if conf.debug_match:
230            debug.sent = PacketList(remain[:], "Sent")
231            debug.match = SndRcvList(self.ans[:])
232
233        # Clean the ans list to delete the field _answered
234        if multi:
235            for snd, _ in self.ans:
236                if hasattr(snd, '_answered'):
237                    del snd._answered
238
239        if verbose:
240            print(
241                "\nReceived %i packets, got %i answers, "
242                "remaining %i packets" % (
243                    self.nbrecv + len(self.ans), len(self.ans),
244                    max(0, self.notans - self.noans)
245                )
246            )
247
248        self.ans_result = SndRcvList(self.ans)
249        self.unans_result = PacketList(remain, "Unanswered")
250
251    def results(self):
252        # type: () -> Tuple[SndRcvList, PacketList]
253        return self.ans_result, self.unans_result
254
255    def _stop_sniffer_if_done(self) -> None:
256        """Close the sniffer if all expected answers have been received"""
257        if self._send_done and self.noans >= self.notans and not self.multi:
258            if self.sniffer and self.sniffer.running:
259                self.sniffer.stop(join=False)
260
261    def _sndrcv_snd(self):
262        # type: () -> None
263        """Function used in the sending thread of sndrcv()"""
264        i = 0
265        p = None
266        try:
267            if self.verbose:
268                os.write(1, b"Begin emission\n")
269            for p in self.tobesent:
270                # Populate the dictionary of _sndrcv_rcv
271                # _sndrcv_rcv won't miss the answer of a packet that
272                # has not been sent
273                self.hsent.setdefault(p.hashret(), []).append(p)
274                # Send packet
275                self.pks.send(p)
276                time.sleep(self.inter)
277                if self.breakout.is_set():
278                    break
279                i += 1
280            if self.verbose:
281                os.write(1, b"\nFinished sending %i packets\n" % i)
282        except SystemExit:
283            pass
284        except Exception:
285            if self.chainEX:
286                raise
287            else:
288                log_runtime.exception("--- Error sending packets")
289        finally:
290            try:
291                cast(Packet, self.tobesent).sent_time = \
292                    cast(Packet, p).sent_time
293            except AttributeError:
294                pass
295            if self._flood:
296                self.notans = self._flood.iterlen
297            elif not self._send_done:
298                self.notans = i
299            self._send_done = True
300        self._stop_sniffer_if_done()
301        # In threaded mode, timeout
302        if self.threaded and self.timeout is not None and not self.breakout.is_set():
303            self.breakout.wait(timeout=self.timeout)
304            if self.sniffer and self.sniffer.running:
305                self.sniffer.stop()
306
307    def _process_packet(self, r):
308        # type: (Packet) -> None
309        """Internal function used to process each packet."""
310        if r is None:
311            return
312        ok = False
313        h = r.hashret()
314        if h in self.hsent:
315            hlst = self.hsent[h]
316            for i, sentpkt in enumerate(hlst):
317                if r.answers(sentpkt):
318                    self.ans.append(QueryAnswer(sentpkt, r))
319                    if self.verbose > 1:
320                        os.write(1, b"*")
321                    ok = True
322                    if not self.multi:
323                        del hlst[i]
324                        self.noans += 1
325                    else:
326                        if not hasattr(sentpkt, '_answered'):
327                            self.noans += 1
328                        sentpkt._answered = 1
329                    break
330        self._stop_sniffer_if_done()
331        if not ok:
332            if self.verbose > 1:
333                os.write(1, b".")
334            self.nbrecv += 1
335            if conf.debug_match:
336                debug.recv.append(r)
337
338    def _sndrcv_rcv(self, callback):
339        # type: (Callable[[], None]) -> None
340        """Function used to receive packets and check their hashret"""
341        # This is blocking.
342        self.sniffer = None  # type: Optional[AsyncSniffer]
343        self.sniffer = AsyncSniffer()
344        self.sniffer._run(
345            prn=self._process_packet,
346            timeout=None if self.threaded and not self._flood else self.timeout,
347            store=False,
348            opened_socket=self.rcv_pks,
349            session=self.session,
350            stop_filter=self.stop_filter,
351            started_callback=callback,
352            chainCC=True,
353        )
354
355
356def sndrcv(*args, **kwargs):
357    # type: (*Any, **Any) -> Tuple[SndRcvList, PacketList]
358    """Scapy raw function to send a packet and receive its answer.
359    WARNING: This is an internal function. Using sr/srp/sr1/srp is
360    more appropriate in many cases.
361    """
362    sndrcver = SndRcvHandler(*args, **kwargs)
363    return sndrcver.results()
364
365
366def __gen_send(s,  # type: SuperSocket
367               x,  # type: _PacketIterable
368               inter=0,  # type: int
369               loop=0,  # type: int
370               count=None,  # type: Optional[int]
371               verbose=None,  # type: Optional[int]
372               realtime=False,  # type: bool
373               return_packets=False,  # type: bool
374               *args,  # type: Any
375               **kargs  # type: Any
376               ):
377    # type: (...) -> Optional[PacketList]
378    """
379    An internal function used by send/sendp to actually send the packets,
380    implement the send logic...
381
382    It will take care of iterating through the different packets
383    """
384    if isinstance(x, str):
385        x = conf.raw_layer(load=x)
386    if not isinstance(x, Gen):
387        x = SetGen(x)
388    if verbose is None:
389        verbose = conf.verb
390    n = 0
391    if count is not None:
392        loop = -count
393    elif not loop:
394        loop = -1
395    sent_packets = PacketList() if return_packets else None
396    p = None
397    try:
398        while loop:
399            dt0 = None
400            for p in x:
401                if realtime:
402                    ct = time.time()
403                    if dt0:
404                        st = dt0 + float(p.time) - ct
405                        if st > 0:
406                            time.sleep(st)
407                    else:
408                        dt0 = ct - float(p.time)
409                s.send(p)
410                if sent_packets is not None:
411                    sent_packets.append(p)
412                n += 1
413                if verbose:
414                    os.write(1, b".")
415                time.sleep(inter)
416            if loop < 0:
417                loop += 1
418    except KeyboardInterrupt:
419        pass
420    finally:
421        try:
422            cast(Packet, x).sent_time = cast(Packet, p).sent_time
423        except AttributeError:
424            pass
425    if verbose:
426        print("\nSent %i packets." % n)
427    return sent_packets
428
429
430def _send(x,  # type: _PacketIterable
431          _func,  # type: Callable[[NetworkInterface], Type[SuperSocket]]
432          inter=0,  # type: int
433          loop=0,  # type: int
434          iface=None,  # type: Optional[_GlobInterfaceType]
435          count=None,  # type: Optional[int]
436          verbose=None,  # type: Optional[int]
437          realtime=False,  # type: bool
438          return_packets=False,  # type: bool
439          socket=None,  # type: Optional[SuperSocket]
440          **kargs  # type: Any
441          ):
442    # type: (...) -> Optional[PacketList]
443    """Internal function used by send and sendp"""
444    need_closing = socket is None
445    iface = resolve_iface(iface or conf.iface)
446    socket = socket or _func(iface)(iface=iface, **kargs)
447    results = __gen_send(socket, x, inter=inter, loop=loop,
448                         count=count, verbose=verbose,
449                         realtime=realtime, return_packets=return_packets)
450    if need_closing:
451        socket.close()
452    return results
453
454
455@conf.commands.register
456def send(x,  # type: _PacketIterable
457         **kargs  # type: Any
458         ):
459    # type: (...) -> Optional[PacketList]
460    """
461    Send packets at layer 3
462
463    This determines the interface (or L2 source to use) based on the routing
464    table: conf.route / conf.route6
465
466    :param x: the packets
467    :param inter: time (in s) between two packets (default 0)
468    :param loop: send packet indefinitely (default 0)
469    :param count: number of packets to send (default None=1)
470    :param verbose: verbose mode (default None=conf.verb)
471    :param realtime: check that a packet was sent before sending the next one
472    :param return_packets: return the sent packets
473    :param socket: the socket to use (default is conf.L3socket(kargs))
474    :param monitor: (not on linux) send in monitor mode
475    :returns: None
476    """
477    if "iface" in kargs:
478        # Warn that it isn't used.
479        warnings.warn(
480            "'iface' has no effect on L3 I/O send(). For multicast/link-local "
481            "see https://scapy.readthedocs.io/en/latest/usage.html#multicast",
482            SyntaxWarning,
483        )
484        del kargs["iface"]
485    iface, ipv6 = _interface_selection(x)
486    return _send(
487        x,
488        lambda iface: iface.l3socket(ipv6),
489        iface=iface,
490        **kargs
491    )
492
493
494@conf.commands.register
495def sendp(x,  # type: _PacketIterable
496          iface=None,  # type: Optional[_GlobInterfaceType]
497          iface_hint=None,  # type: Optional[str]
498          socket=None,  # type: Optional[SuperSocket]
499          **kargs  # type: Any
500          ):
501    # type: (...) -> Optional[PacketList]
502    """
503    Send packets at layer 2
504
505    :param x: the packets
506    :param inter: time (in s) between two packets (default 0)
507    :param loop: send packet indefinitely (default 0)
508    :param count: number of packets to send (default None=1)
509    :param verbose: verbose mode (default None=conf.verb)
510    :param realtime: check that a packet was sent before sending the next one
511    :param return_packets: return the sent packets
512    :param socket: the socket to use (default is conf.L3socket(kargs))
513    :param iface: the interface to send the packets on
514    :param monitor: (not on linux) send in monitor mode
515    :returns: None
516    """
517    if iface is None and iface_hint is not None and socket is None:
518        iface = conf.route.route(iface_hint)[0]
519    return _send(
520        x,
521        lambda iface: iface.l2socket(),
522        iface=iface,
523        socket=socket,
524        **kargs
525    )
526
527
528@conf.commands.register
529def sendpfast(x: _PacketIterable,
530              pps: Optional[float] = None,
531              mbps: Optional[float] = None,
532              realtime: bool = False,
533              count: Optional[int] = None,
534              loop: int = 0,
535              file_cache: bool = False,
536              iface: Optional[_GlobInterfaceType] = None,
537              replay_args: Optional[List[str]] = None,
538              parse_results: bool = False,
539              ):
540    # type: (...) -> Optional[Dict[str, Any]]
541    """Send packets at layer 2 using tcpreplay for performance
542
543    :param pps:  packets per second
544    :param mbps: MBits per second
545    :param realtime: use packet's timestamp, bending time with real-time value
546    :param loop: send the packet indefinitely (default 0)
547    :param count: number of packets to send (default None=1)
548    :param file_cache: cache packets in RAM instead of reading from
549        disk at each iteration
550    :param iface: output interface
551    :param replay_args: List of additional tcpreplay args (List[str])
552    :param parse_results: Return a dictionary of information
553        outputted by tcpreplay (default=False)
554    :returns: stdout, stderr, command used
555    """
556    if iface is None:
557        iface = conf.iface
558    argv = [conf.prog.tcpreplay, "--intf1=%s" % network_name(iface)]
559    if pps is not None:
560        argv.append("--pps=%f" % pps)
561    elif mbps is not None:
562        argv.append("--mbps=%f" % mbps)
563    elif realtime is not None:
564        argv.append("--multiplier=%f" % realtime)
565    else:
566        argv.append("--topspeed")
567
568    if count:
569        assert not loop, "Can't use loop and count at the same time in sendpfast"
570        argv.append("--loop=%i" % count)
571    elif loop:
572        argv.append("--loop=0")
573    if file_cache:
574        argv.append("--preload-pcap")
575
576    # Check for any additional args we didn't cover.
577    if replay_args is not None:
578        argv.extend(replay_args)
579
580    f = get_temp_file()
581    argv.append(f)
582    wrpcap(f, x)
583    results = None
584    with ContextManagerSubprocess(conf.prog.tcpreplay):
585        try:
586            cmd = subprocess.Popen(argv, stdout=subprocess.PIPE,
587                                   stderr=subprocess.PIPE)
588        except KeyboardInterrupt:
589            log_interactive.info("Interrupted by user")
590        except Exception:
591            os.unlink(f)
592            raise
593        else:
594            stdout, stderr = cmd.communicate()
595            if stderr:
596                log_runtime.warning(stderr.decode())
597            if parse_results:
598                results = _parse_tcpreplay_result(stdout, stderr, argv)
599            elif conf.verb > 2:
600                log_runtime.info(stdout.decode())
601    if os.path.exists(f):
602        os.unlink(f)
603    return results
604
605
606def _parse_tcpreplay_result(stdout_b, stderr_b, argv):
607    # type: (bytes, bytes, List[str]) -> Dict[str, Any]
608    """
609    Parse the output of tcpreplay and modify the results_dict to populate output information.  # noqa: E501
610    Tested with tcpreplay v3.4.4
611    Tested with tcpreplay v4.1.2
612    :param stdout: stdout of tcpreplay subprocess call
613    :param stderr: stderr of tcpreplay subprocess call
614    :param argv: the command used in the subprocess call
615    :return: dictionary containing the results
616    """
617    try:
618        results = {}
619        stdout = plain_str(stdout_b).lower()
620        stderr = plain_str(stderr_b).strip().split("\n")
621        elements = {
622            "actual": (int, int, float),
623            "rated": (float, float, float),
624            "flows": (int, float, int, int),
625            "attempted": (int,),
626            "successful": (int,),
627            "failed": (int,),
628            "truncated": (int,),
629            "retried packets (eno": (int,),
630            "retried packets (eag": (int,),
631        }
632        multi = {
633            "actual": ("packets", "bytes", "time"),
634            "rated": ("bps", "mbps", "pps"),
635            "flows": ("flows", "fps", "flow_packets", "non_flow"),
636            "retried packets (eno": ("retried_enobufs",),
637            "retried packets (eag": ("retried_eagain",),
638        }
639        float_reg = r"([0-9]*\.[0-9]+|[0-9]+)"
640        int_reg = r"([0-9]+)"
641        any_reg = r"[^0-9]*"
642        r_types = {int: int_reg, float: float_reg}
643        for line in stdout.split("\n"):
644            line = line.strip()
645            for elt, _types in elements.items():
646                if line.startswith(elt):
647                    regex = any_reg.join([r_types[x] for x in _types])
648                    matches = re.search(regex, line)
649                    for i, typ in enumerate(_types):
650                        name = multi.get(elt, [elt])[i]
651                        if matches:
652                            results[name] = typ(matches.group(i + 1))
653        results["command"] = " ".join(argv)
654        results["warnings"] = stderr[:-1]
655        return results
656    except Exception as parse_exception:
657        if not conf.interactive:
658            raise
659        log_runtime.error("Error parsing output: %s", parse_exception)
660        return {}
661
662
663def _interface_selection(packet: _PacketIterable) -> Tuple[NetworkInterface, bool]:
664    """
665    Select the network interface according to the layer 3 destination
666    """
667    _iff, src, _ = next(packet.__iter__()).route()
668    ipv6 = False
669    if src:
670        try:
671            inet_pton(socket.AF_INET6, src)
672            ipv6 = True
673        except (ValueError, OSError):
674            pass
675    try:
676        iff = resolve_iface(_iff or conf.iface)
677    except AttributeError:
678        iff = None
679    return iff or conf.iface, ipv6
680
681
682@conf.commands.register
683def sr(x,  # type: _PacketIterable
684       promisc=None,  # type: Optional[bool]
685       filter=None,  # type: Optional[str]
686       nofilter=0,  # type: int
687       *args,  # type: Any
688       **kargs  # type: Any
689       ):
690    # type: (...) -> Tuple[SndRcvList, PacketList]
691    """
692    Send and receive packets at layer 3
693
694    This determines the interface (or L2 source to use) based on the routing
695    table: conf.route / conf.route6
696    """
697    if "iface" in kargs:
698        # Warn that it isn't used.
699        warnings.warn(
700            "'iface' has no effect on L3 I/O sr(). For multicast/link-local "
701            "see https://scapy.readthedocs.io/en/latest/usage.html#multicast",
702            SyntaxWarning,
703        )
704        del kargs["iface"]
705    iface, ipv6 = _interface_selection(x)
706    s = iface.l3socket(ipv6)(
707        promisc=promisc, filter=filter,
708        iface=iface, nofilter=nofilter,
709    )
710    result = sndrcv(s, x, *args, **kargs)
711    s.close()
712    return result
713
714
715@conf.commands.register
716def sr1(*args, **kargs):
717    # type: (*Any, **Any) -> Optional[Packet]
718    """
719    Send packets at layer 3 and return only the first answer
720
721    This determines the interface (or L2 source to use) based on the routing
722    table: conf.route / conf.route6
723    """
724    if "iface" in kargs:
725        # Warn that it isn't used.
726        warnings.warn(
727            "'iface' has no effect on L3 I/O sr1(). For multicast/link-local "
728            "see https://scapy.readthedocs.io/en/latest/usage.html#multicast",
729            SyntaxWarning,
730        )
731        del kargs["iface"]
732    ans, _ = sr(*args, **kargs)
733    if ans:
734        return cast(Packet, ans[0][1])
735    return None
736
737
738@conf.commands.register
739def srp(x,  # type: _PacketIterable
740        promisc=None,  # type: Optional[bool]
741        iface=None,  # type: Optional[_GlobInterfaceType]
742        iface_hint=None,  # type: Optional[str]
743        filter=None,  # type: Optional[str]
744        nofilter=0,  # type: int
745        type=ETH_P_ALL,  # type: int
746        *args,  # type: Any
747        **kargs  # type: Any
748        ):
749    # type: (...) -> Tuple[SndRcvList, PacketList]
750    """
751    Send and receive packets at layer 2
752    """
753    if iface is None and iface_hint is not None:
754        iface = conf.route.route(iface_hint)[0]
755    iface = resolve_iface(iface or conf.iface)
756    s = iface.l2socket()(promisc=promisc, iface=iface,
757                         filter=filter, nofilter=nofilter, type=type)
758    result = sndrcv(s, x, *args, **kargs)
759    s.close()
760    return result
761
762
763@conf.commands.register
764def srp1(*args, **kargs):
765    # type: (*Any, **Any) -> Optional[Packet]
766    """
767    Send and receive packets at layer 2 and return only the first answer
768    """
769    ans, _ = srp(*args, **kargs)
770    if len(ans) > 0:
771        return cast(Packet, ans[0][1])
772    return None
773
774
775# Append doc
776for sr_func in [srp, srp1, sr, sr1]:
777    if sr_func.__doc__ is not None:
778        sr_func.__doc__ += _DOC_SNDRCV_PARAMS
779
780
781# SEND/RECV LOOP METHODS
782
783
784def __sr_loop(srfunc,  # type: Callable[..., Tuple[SndRcvList, PacketList]]
785              pkts,  # type: _PacketIterable
786              prn=lambda x: x[1].summary(),  # type: Optional[Callable[[QueryAnswer], Any]]  # noqa: E501
787              prnfail=lambda x: x.summary(),  # type: Optional[Callable[[Packet], Any]]
788              inter=1,  # type: int
789              timeout=None,  # type: Optional[int]
790              count=None,  # type: Optional[int]
791              verbose=None,  # type: Optional[int]
792              store=1,  # type: int
793              *args,  # type: Any
794              **kargs  # type: Any
795              ):
796    # type: (...) -> Tuple[SndRcvList, PacketList]
797    n = 0
798    r = 0
799    ct = conf.color_theme
800    if verbose is None:
801        verbose = conf.verb
802    parity = 0
803    ans = []  # type: List[QueryAnswer]
804    unans = []  # type: List[Packet]
805    if timeout is None:
806        timeout = min(2 * inter, 5)
807    try:
808        while True:
809            parity ^= 1
810            col = [ct.even, ct.odd][parity]
811            if count is not None:
812                if count == 0:
813                    break
814                count -= 1
815            start = time.monotonic()
816            if verbose > 1:
817                print("\rsend...\r", end=' ')
818            res = srfunc(pkts, timeout=timeout, verbose=0, chainCC=True, *args, **kargs)  # noqa: E501
819            n += len(res[0]) + len(res[1])
820            r += len(res[0])
821            if verbose > 1 and prn and len(res[0]) > 0:
822                msg = "RECV %i:" % len(res[0])
823                print("\r" + ct.success(msg), end=' ')
824                for rcv in res[0]:
825                    print(col(prn(rcv)))
826                    print(" " * len(msg), end=' ')
827            if verbose > 1 and prnfail and len(res[1]) > 0:
828                msg = "fail %i:" % len(res[1])
829                print("\r" + ct.fail(msg), end=' ')
830                for fail in res[1]:
831                    print(col(prnfail(fail)))
832                    print(" " * len(msg), end=' ')
833            if verbose > 1 and not (prn or prnfail):
834                print("recv:%i  fail:%i" % tuple(
835                    map(len, res[:2])  # type: ignore
836                ))
837            if verbose == 1:
838                if res[0]:
839                    os.write(1, b"*")
840                if res[1]:
841                    os.write(1, b".")
842            if store:
843                ans += res[0]
844                unans += res[1]
845            end = time.monotonic()
846            if end - start < inter:
847                time.sleep(inter + start - end)
848    except KeyboardInterrupt:
849        pass
850
851    if verbose and n > 0:
852        print(ct.normal("\nSent %i packets, received %i packets. %3.1f%% hits." % (n, r, 100.0 * r / n)))  # noqa: E501
853    return SndRcvList(ans), PacketList(unans)
854
855
856@conf.commands.register
857def srloop(pkts,  # type: _PacketIterable
858           *args,  # type: Any
859           **kargs  # type: Any
860           ):
861    # type: (...) -> Tuple[SndRcvList, PacketList]
862    """
863    Send a packet at layer 3 in loop and print the answer each time
864    srloop(pkts, [prn], [inter], [count], ...) --> None
865    """
866    return __sr_loop(sr, pkts, *args, **kargs)
867
868
869@conf.commands.register
870def srploop(pkts,  # type: _PacketIterable
871            *args,  # type: Any
872            **kargs  # type: Any
873            ):
874    # type: (...) -> Tuple[SndRcvList, PacketList]
875    """
876    Send a packet at layer 2 in loop and print the answer each time
877    srloop(pkts, [prn], [inter], [count], ...) --> None
878    """
879    return __sr_loop(srp, pkts, *args, **kargs)
880
881# SEND/RECV FLOOD METHODS
882
883
884class _FloodGenerator(object):
885    def __init__(self, tobesent, maxretries):
886        # type: (_PacketIterable, Optional[int]) -> None
887        self.tobesent = tobesent
888        self.maxretries = maxretries
889        self.stopevent = Event()
890        self.iterlen = 0
891
892    def __iter__(self):
893        # type: () -> Iterator[Packet]
894        i = 0
895        while True:
896            i += 1
897            j = 0
898            if self.maxretries and i >= self.maxretries:
899                return
900            for p in self.tobesent:
901                if self.stopevent.is_set():
902                    return
903                j += 1
904                yield p
905            if self.iterlen == 0:
906                self.iterlen = j
907
908    @property
909    def sent_time(self):
910        # type: () -> Union[EDecimal, float, None]
911        return cast(Packet, self.tobesent).sent_time
912
913    @sent_time.setter
914    def sent_time(self, val):
915        # type: (Union[EDecimal, float, None]) -> None
916        cast(Packet, self.tobesent).sent_time = val
917
918    def stop(self):
919        # type: () -> None
920        self.stopevent.set()
921
922
923def sndrcvflood(pks,  # type: SuperSocket
924                pkt,  # type: _PacketIterable
925                inter=0,  # type: int
926                maxretries=None,  # type: Optional[int]
927                verbose=None,  # type: Optional[int]
928                chainCC=False,  # type: bool
929                timeout=None  # type: Optional[int]
930                ):
931    # type: (...) -> Tuple[SndRcvList, PacketList]
932    """sndrcv equivalent for flooding."""
933
934    flood_gen = _FloodGenerator(pkt, maxretries)
935    return sndrcv(
936        pks, flood_gen,
937        inter=inter, verbose=verbose,
938        chainCC=chainCC, timeout=timeout,
939        _flood=flood_gen
940    )
941
942
943@conf.commands.register
944def srflood(x,  # type: _PacketIterable
945            promisc=None,  # type: Optional[bool]
946            filter=None,  # type: Optional[str]
947            iface=None,  # type: Optional[_GlobInterfaceType]
948            nofilter=None,  # type: Optional[bool]
949            *args,  # type: Any
950            **kargs  # type: Any
951            ):
952    # type: (...) -> Tuple[SndRcvList, PacketList]
953    """Flood and receive packets at layer 3
954
955    This determines the interface (or L2 source to use) based on the routing
956    table: conf.route / conf.route6
957
958    :param prn:      function applied to packets received
959    :param unique:   only consider packets whose print
960    :param nofilter: put 1 to avoid use of BPF filters
961    :param filter:   provide a BPF filter
962    """
963    if "iface" in kargs:
964        # Warn that it isn't used.
965        warnings.warn(
966            "'iface' has no effect on L3 I/O srflood(). For multicast/link-local "
967            "see https://scapy.readthedocs.io/en/latest/usage.html#multicast",
968            SyntaxWarning,
969        )
970        del kargs["iface"]
971    iface, ipv6 = _interface_selection(x)
972    s = iface.l3socket(ipv6)(
973        promisc=promisc, filter=filter,
974        iface=iface, nofilter=nofilter,
975    )
976    r = sndrcvflood(s, x, *args, **kargs)
977    s.close()
978    return r
979
980
981@conf.commands.register
982def sr1flood(x,  # type: _PacketIterable
983             promisc=None,  # type: Optional[bool]
984             filter=None,  # type: Optional[str]
985             nofilter=0,  # type: int
986             *args,  # type: Any
987             **kargs  # type: Any
988             ):
989    # type: (...) -> Optional[Packet]
990    """Flood and receive packets at layer 3 and return only the first answer
991
992    This determines the interface (or L2 source to use) based on the routing
993    table: conf.route / conf.route6
994
995    :param prn:      function applied to packets received
996    :param verbose:  set verbosity level
997    :param nofilter: put 1 to avoid use of BPF filters
998    :param filter:   provide a BPF filter
999    :param iface:    listen answers only on the given interface
1000    """
1001    if "iface" in kargs:
1002        # Warn that it isn't used.
1003        warnings.warn(
1004            "'iface' has no effect on L3 I/O sr1flood(). For multicast/link-local "
1005            "see https://scapy.readthedocs.io/en/latest/usage.html#multicast",
1006            SyntaxWarning,
1007        )
1008        del kargs["iface"]
1009    iface, ipv6 = _interface_selection(x)
1010    s = iface.l3socket(ipv6)(
1011        promisc=promisc, filter=filter,
1012        nofilter=nofilter, iface=iface,
1013    )
1014    ans, _ = sndrcvflood(s, x, *args, **kargs)
1015    s.close()
1016    if len(ans) > 0:
1017        return cast(Packet, ans[0][1])
1018    return None
1019
1020
1021@conf.commands.register
1022def srpflood(x,  # type: _PacketIterable
1023             promisc=None,  # type: Optional[bool]
1024             filter=None,  # type: Optional[str]
1025             iface=None,  # type: Optional[_GlobInterfaceType]
1026             iface_hint=None,  # type: Optional[str]
1027             nofilter=None,  # type: Optional[bool]
1028             *args,  # type: Any
1029             **kargs  # type: Any
1030             ):
1031    # type: (...) -> Tuple[SndRcvList, PacketList]
1032    """Flood and receive packets at layer 2
1033
1034    :param prn:      function applied to packets received
1035    :param unique:   only consider packets whose print
1036    :param nofilter: put 1 to avoid use of BPF filters
1037    :param filter:   provide a BPF filter
1038    :param iface:    listen answers only on the given interface
1039    """
1040    if iface is None and iface_hint is not None:
1041        iface = conf.route.route(iface_hint)[0]
1042    iface = resolve_iface(iface or conf.iface)
1043    s = iface.l2socket()(promisc=promisc, filter=filter, iface=iface, nofilter=nofilter)  # noqa: E501
1044    r = sndrcvflood(s, x, *args, **kargs)
1045    s.close()
1046    return r
1047
1048
1049@conf.commands.register
1050def srp1flood(x,  # type: _PacketIterable
1051              promisc=None,  # type: Optional[bool]
1052              filter=None,  # type: Optional[str]
1053              iface=None,  # type: Optional[_GlobInterfaceType]
1054              nofilter=0,  # type: int
1055              *args,  # type: Any
1056              **kargs  # type: Any
1057              ):
1058    # type: (...) -> Optional[Packet]
1059    """Flood and receive packets at layer 2 and return only the first answer
1060
1061    :param prn:      function applied to packets received
1062    :param verbose:  set verbosity level
1063    :param nofilter: put 1 to avoid use of BPF filters
1064    :param filter:   provide a BPF filter
1065    :param iface:    listen answers only on the given interface
1066    """
1067    iface = resolve_iface(iface or conf.iface)
1068    s = iface.l2socket()(promisc=promisc, filter=filter, nofilter=nofilter, iface=iface)  # noqa: E501
1069    ans, _ = sndrcvflood(s, x, *args, **kargs)
1070    s.close()
1071    if len(ans) > 0:
1072        return cast(Packet, ans[0][1])
1073    return None
1074
1075# SNIFF METHODS
1076
1077
1078class AsyncSniffer(object):
1079    """
1080    Sniff packets and return a list of packets.
1081
1082    Args:
1083        count: number of packets to capture. 0 means infinity.
1084        store: whether to store sniffed packets or discard them
1085        prn: function to apply to each packet. If something is returned, it
1086             is displayed.
1087             --Ex: prn = lambda x: x.summary()
1088        session: a session = a flow decoder used to handle stream of packets.
1089                 --Ex: session=TCPSession
1090                 See below for more details.
1091        filter: BPF filter to apply.
1092        lfilter: Python function applied to each packet to determine if
1093                 further action may be done.
1094                 --Ex: lfilter = lambda x: x.haslayer(Padding)
1095        offline: PCAP file (or list of PCAP files) to read packets from,
1096                 instead of sniffing them
1097        quiet:   when set to True, the process stderr is discarded
1098                 (default: False).
1099        timeout: stop sniffing after a given time (default: None).
1100        L2socket: use the provided L2socket (default: use conf.L2listen).
1101        opened_socket: provide an object (or a list of objects) ready to use
1102                      .recv() on.
1103        stop_filter: Python function applied to each packet to determine if
1104                     we have to stop the capture after this packet.
1105                     --Ex: stop_filter = lambda x: x.haslayer(TCP)
1106        iface: interface or list of interfaces (default: None for sniffing
1107               on the default interface).
1108        monitor: use monitor mode. May not be available on all OS
1109        started_callback: called as soon as the sniffer starts sniffing
1110                          (default: None).
1111
1112    The iface, offline and opened_socket parameters can be either an
1113    element, a list of elements, or a dict object mapping an element to a
1114    label (see examples below).
1115
1116    For more information about the session argument, see
1117    https://scapy.rtfd.io/en/latest/usage.html#advanced-sniffing-sniffing-sessions
1118
1119    Examples: synchronous
1120      >>> sniff(filter="arp")
1121      >>> sniff(filter="tcp",
1122      ...       session=IPSession,  # defragment on-the-flow
1123      ...       prn=lambda x: x.summary())
1124      >>> sniff(lfilter=lambda pkt: ARP in pkt)
1125      >>> sniff(iface="eth0", prn=Packet.summary)
1126      >>> sniff(iface=["eth0", "mon0"],
1127      ...       prn=lambda pkt: "%s: %s" % (pkt.sniffed_on,
1128      ...                                   pkt.summary()))
1129      >>> sniff(iface={"eth0": "Ethernet", "mon0": "Wifi"},
1130      ...       prn=lambda pkt: "%s: %s" % (pkt.sniffed_on,
1131      ...                                   pkt.summary()))
1132
1133    Examples: asynchronous
1134      >>> t = AsyncSniffer(iface="enp0s3")
1135      >>> t.start()
1136      >>> time.sleep(1)
1137      >>> print("nice weather today")
1138      >>> t.stop()
1139    """
1140
1141    def __init__(self, *args, **kwargs):
1142        # type: (*Any, **Any) -> None
1143        # Store keyword arguments
1144        self.args = args
1145        self.kwargs = kwargs
1146        self.running = False
1147        self.thread = None  # type: Optional[Thread]
1148        self.results = None  # type: Optional[PacketList]
1149        self.exception = None  # type: Optional[Exception]
1150
1151    def _setup_thread(self):
1152        # type: () -> None
1153        def _run_catch(self=self, *args, **kwargs):
1154            # type: (Any, *Any, **Any) -> None
1155            try:
1156                self._run(*args, **kwargs)
1157            except Exception as ex:
1158                self.exception = ex
1159        # Prepare sniffing thread
1160        self.thread = Thread(
1161            target=_run_catch,
1162            args=self.args,
1163            kwargs=self.kwargs,
1164            name="AsyncSniffer"
1165        )
1166        self.thread.daemon = True
1167
1168    def _run(self,
1169             count=0,  # type: int
1170             store=True,  # type: bool
1171             offline=None,  # type: Any
1172             quiet=False,  # type: bool
1173             prn=None,  # type: Optional[Callable[[Packet], Any]]
1174             lfilter=None,  # type: Optional[Callable[[Packet], bool]]
1175             L2socket=None,  # type: Optional[Type[SuperSocket]]
1176             timeout=None,  # type: Optional[int]
1177             opened_socket=None,  # type: Optional[SuperSocket]
1178             stop_filter=None,  # type: Optional[Callable[[Packet], bool]]
1179             iface=None,  # type: Optional[_GlobInterfaceType]
1180             started_callback=None,  # type: Optional[Callable[[], Any]]
1181             session=None,  # type: Optional[_GlobSessionType]
1182             chainCC=False,  # type: bool
1183             **karg  # type: Any
1184             ):
1185        # type: (...) -> None
1186        self.running = True
1187        self.count = 0
1188        lst = []
1189        # Start main thread
1190        # instantiate session
1191        if not isinstance(session, DefaultSession):
1192            session = session or DefaultSession
1193            session = session()
1194        # sniff_sockets follows: {socket: label}
1195        sniff_sockets = {}  # type: Dict[SuperSocket, _GlobInterfaceType]
1196        if opened_socket is not None:
1197            if isinstance(opened_socket, list):
1198                sniff_sockets.update(
1199                    (s, "socket%d" % i)
1200                    for i, s in enumerate(opened_socket)
1201                )
1202            elif isinstance(opened_socket, dict):
1203                sniff_sockets.update(
1204                    (s, label)
1205                    for s, label in opened_socket.items()
1206                )
1207            else:
1208                sniff_sockets[opened_socket] = "socket0"
1209        if offline is not None:
1210            flt = karg.get('filter')
1211
1212            if isinstance(offline, str):
1213                # Single file
1214                offline = [offline]
1215            if isinstance(offline, list) and \
1216                    all(isinstance(elt, str) for elt in offline):
1217                # List of files
1218                sniff_sockets.update((PcapReader(  # type: ignore
1219                    fname if flt is None else
1220                    tcpdump(fname,
1221                            args=["-w", "-"],
1222                            flt=flt,
1223                            getfd=True,
1224                            quiet=quiet)
1225                ), fname) for fname in offline)
1226            elif isinstance(offline, dict):
1227                # Dict of files
1228                sniff_sockets.update((PcapReader(  # type: ignore
1229                    fname if flt is None else
1230                    tcpdump(fname,
1231                            args=["-w", "-"],
1232                            flt=flt,
1233                            getfd=True,
1234                            quiet=quiet)
1235                ), label) for fname, label in offline.items())
1236            elif isinstance(offline, (Packet, PacketList, list)):
1237                # Iterables (list of packets, PacketList..)
1238                offline = IterSocket(offline)
1239                sniff_sockets[offline if flt is None else PcapReader(
1240                    tcpdump(offline,
1241                            args=["-w", "-"],
1242                            flt=flt,
1243                            getfd=True,
1244                            quiet=quiet)
1245                )] = offline
1246            else:
1247                # Other (file descriptors...)
1248                sniff_sockets[PcapReader(  # type: ignore
1249                    offline if flt is None else
1250                    tcpdump(offline,
1251                            args=["-w", "-"],
1252                            flt=flt,
1253                            getfd=True,
1254                            quiet=quiet)
1255                )] = offline
1256        if not sniff_sockets or iface is not None:
1257            # The _RL2 function resolves the L2socket of an iface
1258            _RL2 = lambda i: L2socket or resolve_iface(i).l2listen()  # type: Callable[[_GlobInterfaceType], Callable[..., SuperSocket]]  # noqa: E501
1259            if isinstance(iface, list):
1260                sniff_sockets.update(
1261                    (_RL2(ifname)(type=ETH_P_ALL, iface=ifname, **karg),
1262                     ifname)
1263                    for ifname in iface
1264                )
1265            elif isinstance(iface, dict):
1266                sniff_sockets.update(
1267                    (_RL2(ifname)(type=ETH_P_ALL, iface=ifname, **karg),
1268                     iflabel)
1269                    for ifname, iflabel in iface.items()
1270                )
1271            else:
1272                iface = iface or conf.iface
1273                sniff_sockets[_RL2(iface)(type=ETH_P_ALL, iface=iface,
1274                                          **karg)] = iface
1275
1276        # Get select information from the sockets
1277        _main_socket = next(iter(sniff_sockets))
1278        select_func = _main_socket.select
1279        nonblocking_socket = getattr(_main_socket, "nonblocking_socket", False)
1280        # We check that all sockets use the same select(), or raise a warning
1281        if not all(select_func == sock.select for sock in sniff_sockets):
1282            warning("Warning: inconsistent socket types ! "
1283                    "The used select function "
1284                    "will be the one of the first socket")
1285
1286        close_pipe = None  # type: Optional[ObjectPipe[None]]
1287        if not nonblocking_socket:
1288            # select is blocking: Add special control socket
1289            from scapy.automaton import ObjectPipe
1290            close_pipe = ObjectPipe[None]("control_socket")
1291            sniff_sockets[close_pipe] = "control_socket"  # type: ignore
1292
1293            def stop_cb():
1294                # type: () -> None
1295                if self.running and close_pipe:
1296                    close_pipe.send(None)
1297                self.continue_sniff = False
1298            self.stop_cb = stop_cb
1299        else:
1300            # select is non blocking
1301            def stop_cb():
1302                # type: () -> None
1303                self.continue_sniff = False
1304            self.stop_cb = stop_cb
1305
1306        try:
1307            if started_callback:
1308                started_callback()
1309            self.continue_sniff = True
1310
1311            # Start timeout
1312            if timeout is not None:
1313                stoptime = time.monotonic() + timeout
1314            remain = None
1315
1316            while sniff_sockets and self.continue_sniff:
1317                if timeout is not None:
1318                    remain = stoptime - time.monotonic()
1319                    if remain <= 0:
1320                        break
1321                sockets = select_func(list(sniff_sockets.keys()), remain)
1322                dead_sockets = []
1323                for s in sockets:
1324                    if s is close_pipe:  # type: ignore
1325                        break
1326                    # The session object is passed the socket to call recv() on,
1327                    # and may perform additional processing (ip defrag, etc.)
1328                    try:
1329                        packets = session.recv(s)
1330                        # A session can return multiple objects
1331                        for p in packets:
1332                            if lfilter and not lfilter(p):
1333                                continue
1334                            p.sniffed_on = sniff_sockets.get(s, None)
1335                            # post-processing
1336                            self.count += 1
1337                            if store:
1338                                lst.append(p)
1339                            if prn:
1340                                result = prn(p)
1341                                if result is not None:
1342                                    print(result)
1343                            # check
1344                            if (stop_filter and stop_filter(p)) or \
1345                                    (0 < count <= self.count):
1346                                self.continue_sniff = False
1347                                break
1348                    except EOFError:
1349                        # End of stream
1350                        try:
1351                            s.close()
1352                        except Exception:
1353                            pass
1354                        dead_sockets.append(s)
1355                        continue
1356                    except Exception as ex:
1357                        msg = " It was closed."
1358                        try:
1359                            # Make sure it's closed
1360                            s.close()
1361                        except Exception as ex2:
1362                            msg = " close() failed with '%s'" % ex2
1363                        warning(
1364                            "Socket %s failed with '%s'." % (s, ex) + msg
1365                        )
1366                        dead_sockets.append(s)
1367                        if conf.debug_dissector >= 2:
1368                            raise
1369                        continue
1370                # Removed dead sockets
1371                for s in dead_sockets:
1372                    del sniff_sockets[s]
1373                    if len(sniff_sockets) == 1 and \
1374                            close_pipe in sniff_sockets:  # type: ignore
1375                        # Only the close_pipe left
1376                        del sniff_sockets[close_pipe]  # type: ignore
1377        except KeyboardInterrupt:
1378            if chainCC:
1379                raise
1380        self.running = False
1381        if opened_socket is None:
1382            for s in sniff_sockets:
1383                s.close()
1384        elif close_pipe:
1385            close_pipe.close()
1386        self.results = PacketList(lst, "Sniffed")
1387
1388    def start(self):
1389        # type: () -> None
1390        """Starts AsyncSniffer in async mode"""
1391        self._setup_thread()
1392        if self.thread:
1393            self.thread.start()
1394
1395    def stop(self, join=True):
1396        # type: (bool) -> Optional[PacketList]
1397        """Stops AsyncSniffer if not in async mode"""
1398        if self.running:
1399            try:
1400                self.stop_cb()
1401            except AttributeError:
1402                raise Scapy_Exception(
1403                    "Unsupported (offline or unsupported socket)"
1404                )
1405            if join:
1406                self.join()
1407                return self.results
1408            return None
1409        else:
1410            raise Scapy_Exception("Not running ! (check .running attr)")
1411
1412    def join(self, *args, **kwargs):
1413        # type: (*Any, **Any) -> None
1414        if self.thread:
1415            self.thread.join(*args, **kwargs)
1416        if self.exception is not None:
1417            raise self.exception
1418
1419
1420@conf.commands.register
1421def sniff(*args, **kwargs):
1422    # type: (*Any, **Any) -> PacketList
1423    sniffer = AsyncSniffer()
1424    sniffer._run(*args, **kwargs)
1425    return cast(PacketList, sniffer.results)
1426
1427
1428sniff.__doc__ = AsyncSniffer.__doc__
1429
1430
1431@conf.commands.register
1432def bridge_and_sniff(if1,  # type: _GlobInterfaceType
1433                     if2,  # type: _GlobInterfaceType
1434                     xfrm12=None,  # type: Optional[Callable[[Packet], Union[Packet, bool]]]  # noqa: E501
1435                     xfrm21=None,  # type: Optional[Callable[[Packet], Union[Packet, bool]]]  # noqa: E501
1436                     prn=None,  # type: Optional[Callable[[Packet], Any]]
1437                     L2socket=None,  # type: Optional[Type[SuperSocket]]
1438                     *args,  # type: Any
1439                     **kargs  # type: Any
1440                     ):
1441    # type: (...) -> PacketList
1442    """Forward traffic between interfaces if1 and if2, sniff and return
1443    the exchanged packets.
1444
1445    :param if1: the interfaces to use (interface names or opened sockets).
1446    :param if2:
1447    :param xfrm12: a function to call when forwarding a packet from if1 to
1448        if2. If it returns True, the packet is forwarded as it. If it
1449        returns False or None, the packet is discarded. If it returns a
1450        packet, this packet is forwarded instead of the original packet
1451        one.
1452    :param xfrm21: same as xfrm12 for packets forwarded from if2 to if1.
1453
1454    The other arguments are the same than for the function sniff(),
1455    except for offline, opened_socket and iface that are ignored.
1456    See help(sniff) for more.
1457    """
1458    for arg in ['opened_socket', 'offline', 'iface']:
1459        if arg in kargs:
1460            log_runtime.warning("Argument %s cannot be used in "
1461                                "bridge_and_sniff() -- ignoring it.", arg)
1462            del kargs[arg]
1463
1464    def _init_socket(iface,  # type: _GlobInterfaceType
1465                     count,  # type: int
1466                     L2socket=L2socket  # type: Optional[Type[SuperSocket]]
1467                     ):
1468        # type: (...) -> Tuple[SuperSocket, _GlobInterfaceType]
1469        if isinstance(iface, SuperSocket):
1470            return iface, "iface%d" % count
1471        else:
1472            if not L2socket:
1473                iface = resolve_iface(iface or conf.iface)
1474                L2socket = iface.l2socket()
1475            return L2socket(iface=iface), iface
1476    sckt1, if1 = _init_socket(if1, 1)
1477    sckt2, if2 = _init_socket(if2, 2)
1478    peers = {if1: sckt2, if2: sckt1}
1479    xfrms = {}
1480    if xfrm12 is not None:
1481        xfrms[if1] = xfrm12
1482    if xfrm21 is not None:
1483        xfrms[if2] = xfrm21
1484
1485    def prn_send(pkt):
1486        # type: (Packet) -> None
1487        try:
1488            sendsock = peers[pkt.sniffed_on or ""]
1489        except KeyError:
1490            return
1491        if pkt.sniffed_on in xfrms:
1492            try:
1493                _newpkt = xfrms[pkt.sniffed_on](pkt)
1494            except Exception:
1495                log_runtime.warning(
1496                    'Exception in transformation function for packet [%s] '
1497                    'received on %s -- dropping',
1498                    pkt.summary(), pkt.sniffed_on, exc_info=True
1499                )
1500                return
1501            else:
1502                if isinstance(_newpkt, bool):
1503                    if not _newpkt:
1504                        return
1505                    newpkt = pkt
1506                else:
1507                    newpkt = _newpkt
1508        else:
1509            newpkt = pkt
1510        try:
1511            sendsock.send(newpkt)
1512        except Exception:
1513            log_runtime.warning('Cannot forward packet [%s] received on %s',
1514                                pkt.summary(), pkt.sniffed_on, exc_info=True)
1515    if prn is None:
1516        prn = prn_send
1517    else:
1518        prn_orig = prn
1519
1520        def prn(pkt):
1521            # type: (Packet) -> Any
1522            prn_send(pkt)
1523            return prn_orig(pkt)
1524
1525    return sniff(opened_socket={sckt1: if1, sckt2: if2}, prn=prn,
1526                 *args, **kargs)
1527
1528
1529@conf.commands.register
1530def tshark(*args, **kargs):
1531    # type: (Any, Any) -> None
1532    """Sniff packets and print them calling pkt.summary().
1533    This tries to replicate what text-wireshark (tshark) would look like"""
1534
1535    if 'iface' in kargs:
1536        iface = kargs.get('iface')
1537    elif 'opened_socket' in kargs:
1538        iface = cast(SuperSocket, kargs.get('opened_socket')).iface
1539    else:
1540        iface = conf.iface
1541    print("Capturing on '%s'" % iface)
1542
1543    # This should be a nonlocal variable, using a mutable object
1544    # for Python 2 compatibility
1545    i = [0]
1546
1547    def _cb(pkt):
1548        # type: (Packet) -> None
1549        print("%5d\t%s" % (i[0], pkt.summary()))
1550        i[0] += 1
1551
1552    sniff(prn=_cb, store=False, *args, **kargs)
1553    print("\n%d packet%s captured" % (i[0], 's' if i[0] > 1 else ''))
1554