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