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