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