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