Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/sendrecv.py: 13%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

735 statements  

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 first: stop after receiving the first response of any sent packet 

90 :param rcv_pks: if set, will be used instead of pks to receive packets. 

91 packets will still be sent through pks 

92 :param prebuild: pre-build the packets before starting to send them. 

93 Automatically enabled when a generator is passed as the packet 

94 :param _flood: 

95 :param threaded: if True, packets are sent in a thread and received in another. 

96 Defaults to True. 

97 :param session: a flow decoder used to handle stream of packets 

98 :param chainEX: if True, exceptions during send will be forwarded 

99 :param stop_filter: Python function applied to each packet to determine if 

100 we have to stop the capture after this packet. 

101 """ 

102 

103 

104_GlobSessionType = Union[Type[DefaultSession], DefaultSession] 

105 

106 

107class SndRcvHandler(object): 

108 """ 

109 Util to send/receive packets, used by sr*(). 

110 Do not use directly. 

111 

112 This matches the requests and answers. 

113 

114 Notes:: 

115 - threaded: if you're planning to send/receive many packets, it's likely 

116 a good idea to use threaded mode. 

117 - DEVS: store the outgoing timestamp right BEFORE sending the packet 

118 to avoid races that could result in negative latency. We aren't Stadia 

119 """ 

120 def __init__(self, 

121 pks, # type: SuperSocket 

122 pkt, # type: _PacketIterable 

123 timeout=None, # type: Optional[int] 

124 inter=0, # type: int 

125 verbose=None, # type: Optional[int] 

126 chainCC=False, # type: bool 

127 retry=0, # type: int 

128 multi=False, # type: bool 

129 first=False, # type: bool 

130 rcv_pks=None, # type: Optional[SuperSocket] 

131 prebuild=False, # type: bool 

132 _flood=None, # type: Optional[_FloodGenerator] 

133 threaded=True, # type: bool 

134 session=None, # type: Optional[_GlobSessionType] 

135 chainEX=False, # type: bool 

136 stop_filter=None, # type: Optional[Callable[[Packet], bool]] 

137 **send_kwargs, # type: Any 

138 ): 

139 # type: (...) -> None 

140 # Instantiate all arguments 

141 if verbose is None: 

142 verbose = conf.verb 

143 if conf.debug_match: 

144 debug.recv = PacketList([], "Received") 

145 debug.sent = PacketList([], "Sent") 

146 debug.match = SndRcvList([], "Matched") 

147 self.nbrecv = 0 

148 self.ans = [] # type: List[QueryAnswer] 

149 self.pks = pks 

150 self.rcv_pks = rcv_pks or pks 

151 self.inter = inter 

152 self.verbose = verbose 

153 self.chainCC = chainCC 

154 self.multi = multi 

155 self.timeout = timeout 

156 self.first = first 

157 self.session = session 

158 self.chainEX = chainEX 

159 self.stop_filter = stop_filter 

160 self._send_done = False 

161 self.notans = 0 

162 self.noans = 0 

163 self._flood = _flood 

164 self.threaded = threaded 

165 self.breakout = Event() 

166 self.send_kwargs = send_kwargs 

167 # Instantiate packet holders 

168 if prebuild and not self._flood: 

169 self.tobesent = list(pkt) # type: _PacketIterable 

170 else: 

171 self.tobesent = pkt 

172 

173 if retry < 0: 

174 autostop = retry = -retry 

175 else: 

176 autostop = 0 

177 

178 if timeout is not None and timeout < 0: 

179 self.timeout = None 

180 

181 while retry >= 0: 

182 self.breakout.clear() 

183 self.hsent = {} # type: Dict[bytes, List[Packet]] 

184 

185 if threaded or self._flood: 

186 # Send packets in thread. 

187 snd_thread = Thread( 

188 target=self._sndrcv_snd 

189 ) 

190 snd_thread.daemon = True 

191 

192 # Start routine with callback 

193 interrupted = None 

194 try: 

195 self._sndrcv_rcv(snd_thread.start) 

196 except KeyboardInterrupt as ex: 

197 interrupted = ex 

198 

199 self.breakout.set() 

200 

201 # Ended. Let's close gracefully 

202 if self._flood: 

203 # Flood: stop send thread 

204 self._flood.stop() 

205 snd_thread.join() 

206 

207 if interrupted and self.chainCC: 

208 raise interrupted 

209 else: 

210 # Send packets, then receive. 

211 try: 

212 self._sndrcv_rcv(self._sndrcv_snd) 

213 except KeyboardInterrupt: 

214 if self.chainCC: 

215 raise 

216 

217 if multi: 

218 remain = [ 

219 p for p in itertools.chain(*self.hsent.values()) 

220 if not hasattr(p, '_answered') 

221 ] 

222 else: 

223 remain = list(itertools.chain(*self.hsent.values())) 

224 

225 if autostop and len(remain) > 0 and \ 

226 len(remain) != len(self.tobesent): 

227 retry = autostop 

228 

229 self.tobesent = remain 

230 if len(self.tobesent) == 0: 

231 break 

232 retry -= 1 

233 

234 if conf.debug_match: 

235 debug.sent = PacketList(remain[:], "Sent") 

236 debug.match = SndRcvList(self.ans[:]) 

237 

238 # Clean the ans list to delete the field _answered 

239 if multi: 

240 for snd, _ in self.ans: 

241 if hasattr(snd, '_answered'): 

242 del snd._answered 

243 

244 if verbose: 

245 print( 

246 "\nReceived %i packets, got %i answers, " 

247 "remaining %i packets" % ( 

248 self.nbrecv + len(self.ans), len(self.ans), 

249 max(0, self.notans - self.noans) 

250 ) 

251 ) 

252 

253 self.ans_result = SndRcvList(self.ans) 

254 self.unans_result = PacketList(remain, "Unanswered") 

255 

256 def results(self): 

257 # type: () -> Tuple[SndRcvList, PacketList] 

258 return self.ans_result, self.unans_result 

259 

260 def _stop_sniffer_if_done(self) -> None: 

261 """Close the sniffer if all expected answers have been received""" 

262 if ( 

263 self._send_done and self.noans >= self.notans and not self.multi or 

264 self.first and self.noans 

265 ): 

266 if self.sniffer and self.sniffer.running: 

267 self.sniffer.stop(join=False) 

268 

269 def _sndrcv_snd(self): 

270 # type: () -> None 

271 """Function used in the sending thread of sndrcv()""" 

272 i = 0 

273 p = None 

274 try: 

275 if self.verbose: 

276 os.write(1, b"Begin emission\n") 

277 for p in self.tobesent: 

278 # Populate the dictionary of _sndrcv_rcv 

279 # _sndrcv_rcv won't miss the answer of a packet that 

280 # has not been sent 

281 self.hsent.setdefault(p.hashret(), []).append(p) 

282 # Send packet 

283 self.pks.send(p, **self.send_kwargs) 

284 time.sleep(self.inter) 

285 if self.breakout.is_set(): 

286 break 

287 i += 1 

288 if self.verbose: 

289 os.write(1, b"\nFinished sending %i packets\n" % i) 

290 except SystemExit: 

291 pass 

292 except Exception: 

293 if self.chainEX: 

294 raise 

295 else: 

296 log_runtime.exception("--- Error sending packets") 

297 finally: 

298 try: 

299 cast(Packet, self.tobesent).sent_time = \ 

300 cast(Packet, p).sent_time 

301 except AttributeError: 

302 pass 

303 if self._flood: 

304 self.notans = self._flood.iterlen 

305 elif not self._send_done: 

306 self.notans = i 

307 self._send_done = True 

308 self._stop_sniffer_if_done() 

309 # In threaded mode, timeout 

310 if self.threaded and self.timeout is not None and not self.breakout.is_set(): 

311 self.breakout.wait(timeout=self.timeout) 

312 if self.sniffer and self.sniffer.running: 

313 self.sniffer.stop() 

314 

315 def _process_packet(self, r): 

316 # type: (Packet) -> None 

317 """Internal function used to process each packet.""" 

318 if r is None: 

319 return 

320 ok = False 

321 h = r.hashret() 

322 if h in self.hsent: 

323 hlst = self.hsent[h] 

324 for i, sentpkt in enumerate(hlst): 

325 if r.answers(sentpkt): 

326 self.ans.append(QueryAnswer(sentpkt, r)) 

327 if self.verbose > 1: 

328 os.write(1, b"*") 

329 ok = True 

330 if not self.multi: 

331 del hlst[i] 

332 self.noans += 1 

333 else: 

334 if not hasattr(sentpkt, '_answered'): 

335 self.noans += 1 

336 sentpkt._answered = 1 

337 break 

338 self._stop_sniffer_if_done() 

339 if not ok: 

340 if self.verbose > 1: 

341 os.write(1, b".") 

342 self.nbrecv += 1 

343 if conf.debug_match: 

344 debug.recv.append(r) 

345 

346 def _sndrcv_rcv(self, callback): 

347 # type: (Callable[[], None]) -> None 

348 """Function used to receive packets and check their hashret""" 

349 # This is blocking. 

350 self.sniffer = None # type: Optional[AsyncSniffer] 

351 self.sniffer = AsyncSniffer() 

352 self.sniffer._run( 

353 prn=self._process_packet, 

354 timeout=None if self.threaded and not self._flood else self.timeout, 

355 store=False, 

356 opened_socket=self.rcv_pks, 

357 session=self.session, 

358 stop_filter=self.stop_filter, 

359 started_callback=callback, 

360 chainCC=True, 

361 ) 

362 

363 

364def sndrcv(*args, **kwargs): 

365 # type: (*Any, **Any) -> Tuple[SndRcvList, PacketList] 

366 """Scapy raw function to send a packet and receive its answer. 

367 WARNING: This is an internal function. Using sr/srp/sr1/srp is 

368 more appropriate in many cases. 

369 """ 

370 sndrcver = SndRcvHandler(*args, **kwargs) 

371 return sndrcver.results() 

372 

373 

374def __gen_send(s, # type: SuperSocket 

375 x, # type: _PacketIterable 

376 inter=0, # type: int 

377 loop=0, # type: int 

378 count=None, # type: Optional[int] 

379 verbose=None, # type: Optional[int] 

380 realtime=False, # type: bool 

381 return_packets=False, # type: bool 

382 *args, # type: Any 

383 **kargs # type: Any 

384 ): 

385 # type: (...) -> Optional[PacketList] 

386 """ 

387 An internal function used by send/sendp to actually send the packets, 

388 implement the send logic... 

389 

390 It will take care of iterating through the different packets 

391 """ 

392 if isinstance(x, str): 

393 x = conf.raw_layer(load=x) 

394 if not isinstance(x, Gen): 

395 x = SetGen(x) 

396 if verbose is None: 

397 verbose = conf.verb 

398 n = 0 

399 if count is not None: 

400 loop = -count 

401 elif not loop: 

402 loop = -1 

403 sent_packets = PacketList() if return_packets else None 

404 p = None 

405 try: 

406 while loop: 

407 dt0 = None 

408 for p in x: 

409 if realtime: 

410 ct = time.time() 

411 if dt0: 

412 st = dt0 + float(p.time) - ct 

413 if st > 0: 

414 time.sleep(st) 

415 else: 

416 dt0 = ct - float(p.time) 

417 s.send(p) 

418 if sent_packets is not None: 

419 sent_packets.append(p) 

420 n += 1 

421 if verbose: 

422 os.write(1, b".") 

423 time.sleep(inter) 

424 if loop < 0: 

425 loop += 1 

426 except KeyboardInterrupt: 

427 pass 

428 finally: 

429 try: 

430 cast(Packet, x).sent_time = cast(Packet, p).sent_time 

431 except AttributeError: 

432 pass 

433 if verbose: 

434 print("\nSent %i packets." % n) 

435 return sent_packets 

436 

437 

438def _send(x, # type: _PacketIterable 

439 _func, # type: Callable[[NetworkInterface], Type[SuperSocket]] 

440 inter=0, # type: int 

441 loop=0, # type: int 

442 iface=None, # type: Optional[_GlobInterfaceType] 

443 count=None, # type: Optional[int] 

444 verbose=None, # type: Optional[int] 

445 realtime=False, # type: bool 

446 return_packets=False, # type: bool 

447 socket=None, # type: Optional[SuperSocket] 

448 **kargs # type: Any 

449 ): 

450 # type: (...) -> Optional[PacketList] 

451 """Internal function used by send and sendp""" 

452 need_closing = socket is None 

453 iface = resolve_iface(iface or conf.iface) 

454 socket = socket or _func(iface)(iface=iface, **kargs) 

455 results = __gen_send(socket, x, inter=inter, loop=loop, 

456 count=count, verbose=verbose, 

457 realtime=realtime, return_packets=return_packets) 

458 if need_closing: 

459 socket.close() 

460 return results 

461 

462 

463@conf.commands.register 

464def send(x, # type: _PacketIterable 

465 **kargs # type: Any 

466 ): 

467 # type: (...) -> Optional[PacketList] 

468 """ 

469 Send packets at layer 3 

470 

471 This determines the interface (or L2 source to use) based on the routing 

472 table: conf.route / conf.route6 

473 

474 :param x: the packets 

475 :param inter: time (in s) between two packets (default 0) 

476 :param loop: send packet indefinitely (default 0) 

477 :param count: number of packets to send (default None=1) 

478 :param verbose: verbose mode (default None=conf.verb) 

479 :param realtime: check that a packet was sent before sending the next one 

480 :param return_packets: return the sent packets 

481 :param socket: the socket to use (default is conf.L3socket(kargs)) 

482 :param monitor: (not on linux) send in monitor mode 

483 :returns: None 

484 """ 

485 if "iface" in kargs: 

486 # Warn that it isn't used. 

487 warnings.warn( 

488 "'iface' has no effect on L3 I/O send(). For multicast/link-local " 

489 "see https://scapy.readthedocs.io/en/latest/usage.html#multicast", 

490 SyntaxWarning, 

491 ) 

492 del kargs["iface"] 

493 iface, ipv6 = _interface_selection(x) 

494 return _send( 

495 x, 

496 lambda iface: iface.l3socket(ipv6), 

497 iface=iface, 

498 **kargs 

499 ) 

500 

501 

502@conf.commands.register 

503def sendp(x, # type: _PacketIterable 

504 iface=None, # type: Optional[_GlobInterfaceType] 

505 iface_hint=None, # type: Optional[str] 

506 socket=None, # type: Optional[SuperSocket] 

507 **kargs # type: Any 

508 ): 

509 # type: (...) -> Optional[PacketList] 

510 """ 

511 Send packets at layer 2 

512 

513 :param x: the packets 

514 :param inter: time (in s) between two packets (default 0) 

515 :param loop: send packet indefinitely (default 0) 

516 :param count: number of packets to send (default None=1) 

517 :param verbose: verbose mode (default None=conf.verb) 

518 :param realtime: check that a packet was sent before sending the next one 

519 :param return_packets: return the sent packets 

520 :param socket: the socket to use (default is conf.L3socket(kargs)) 

521 :param iface: the interface to send the packets on 

522 :param monitor: (not on linux) send in monitor mode 

523 :returns: None 

524 """ 

525 if iface is None and iface_hint is not None and socket is None: 

526 iface = conf.route.route(iface_hint)[0] 

527 return _send( 

528 x, 

529 lambda iface: iface.l2socket(), 

530 iface=iface, 

531 socket=socket, 

532 **kargs 

533 ) 

534 

535 

536@conf.commands.register 

537def sendpfast(x: _PacketIterable, 

538 pps: Optional[float] = None, 

539 mbps: Optional[float] = None, 

540 realtime: bool = False, 

541 count: Optional[int] = None, 

542 loop: int = 0, 

543 file_cache: bool = False, 

544 iface: Optional[_GlobInterfaceType] = None, 

545 replay_args: Optional[List[str]] = None, 

546 parse_results: bool = False, 

547 ): 

548 # type: (...) -> Optional[Dict[str, Any]] 

549 """Send packets at layer 2 using tcpreplay for performance 

550 

551 :param pps: packets per second 

552 :param mbps: MBits per second 

553 :param realtime: use packet's timestamp, bending time with real-time value 

554 :param loop: send the packet indefinitely (default 0) 

555 :param count: number of packets to send (default None=1) 

556 :param file_cache: cache packets in RAM instead of reading from 

557 disk at each iteration 

558 :param iface: output interface 

559 :param replay_args: List of additional tcpreplay args (List[str]) 

560 :param parse_results: Return a dictionary of information 

561 outputted by tcpreplay (default=False) 

562 :returns: stdout, stderr, command used 

563 """ 

564 if iface is None: 

565 iface = conf.iface 

566 argv = [conf.prog.tcpreplay, "--intf1=%s" % network_name(iface)] 

567 if pps is not None: 

568 argv.append("--pps=%f" % pps) 

569 elif mbps is not None: 

570 argv.append("--mbps=%f" % mbps) 

571 elif realtime is not None: 

572 argv.append("--multiplier=%f" % realtime) 

573 else: 

574 argv.append("--topspeed") 

575 

576 if count: 

577 assert not loop, "Can't use loop and count at the same time in sendpfast" 

578 argv.append("--loop=%i" % count) 

579 elif loop: 

580 argv.append("--loop=0") 

581 if file_cache: 

582 argv.append("--preload-pcap") 

583 

584 # Check for any additional args we didn't cover. 

585 if replay_args is not None: 

586 argv.extend(replay_args) 

587 

588 f = get_temp_file() 

589 argv.append(f) 

590 wrpcap(f, x) 

591 results = None 

592 with ContextManagerSubprocess(conf.prog.tcpreplay): 

593 try: 

594 cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, 

595 stderr=subprocess.PIPE) 

596 cmd.wait() 

597 except KeyboardInterrupt: 

598 if cmd: 

599 cmd.terminate() 

600 log_interactive.info("Interrupted by user") 

601 except Exception: 

602 os.unlink(f) 

603 raise 

604 finally: 

605 stdout, stderr = cmd.communicate() 

606 if stderr: 

607 log_runtime.warning(stderr.decode()) 

608 if parse_results: 

609 results = _parse_tcpreplay_result(stdout, stderr, argv) 

610 elif conf.verb > 2: 

611 log_runtime.info(stdout.decode()) 

612 if os.path.exists(f): 

613 os.unlink(f) 

614 return results 

615 

616 

617def _parse_tcpreplay_result(stdout_b, stderr_b, argv): 

618 # type: (bytes, bytes, List[str]) -> Dict[str, Any] 

619 """ 

620 Parse the output of tcpreplay and modify the results_dict to populate output information. # noqa: E501 

621 Tested with tcpreplay v3.4.4 

622 Tested with tcpreplay v4.1.2 

623 :param stdout: stdout of tcpreplay subprocess call 

624 :param stderr: stderr of tcpreplay subprocess call 

625 :param argv: the command used in the subprocess call 

626 :return: dictionary containing the results 

627 """ 

628 try: 

629 results = {} 

630 stdout = plain_str(stdout_b).lower() 

631 stderr = plain_str(stderr_b).strip().split("\n") 

632 elements = { 

633 "actual": (int, int, float), 

634 "rated": (float, float, float), 

635 "flows": (int, float, int, int), 

636 "attempted": (int,), 

637 "successful": (int,), 

638 "failed": (int,), 

639 "truncated": (int,), 

640 "retried packets (eno": (int,), 

641 "retried packets (eag": (int,), 

642 } 

643 multi = { 

644 "actual": ("packets", "bytes", "time"), 

645 "rated": ("bps", "mbps", "pps"), 

646 "flows": ("flows", "fps", "flow_packets", "non_flow"), 

647 "retried packets (eno": ("retried_enobufs",), 

648 "retried packets (eag": ("retried_eagain",), 

649 } 

650 float_reg = r"([0-9]*\.[0-9]+|[0-9]+)" 

651 int_reg = r"([0-9]+)" 

652 any_reg = r"[^0-9]*" 

653 r_types = {int: int_reg, float: float_reg} 

654 for line in stdout.split("\n"): 

655 line = line.strip() 

656 for elt, _types in elements.items(): 

657 if line.startswith(elt): 

658 regex = any_reg.join([r_types[x] for x in _types]) 

659 matches = re.search(regex, line) 

660 for i, typ in enumerate(_types): 

661 name = multi.get(elt, [elt])[i] 

662 if matches: 

663 results[name] = typ(matches.group(i + 1)) 

664 results["command"] = " ".join(argv) 

665 results["warnings"] = stderr[:-1] 

666 return results 

667 except Exception as parse_exception: 

668 if not conf.interactive: 

669 raise 

670 log_runtime.error("Error parsing output: %s", parse_exception) 

671 return {} 

672 

673 

674def _interface_selection(packet: _PacketIterable) -> Tuple[NetworkInterface, bool]: 

675 """ 

676 Select the network interface according to the layer 3 destination 

677 """ 

678 _iff, src, _ = next(packet.__iter__()).route() 

679 ipv6 = False 

680 if src: 

681 try: 

682 inet_pton(socket.AF_INET6, src) 

683 ipv6 = True 

684 except (ValueError, OSError): 

685 pass 

686 try: 

687 iff = resolve_iface(_iff or conf.iface) 

688 except AttributeError: 

689 iff = None 

690 return iff or conf.iface, ipv6 

691 

692 

693@conf.commands.register 

694def sr(x, # type: _PacketIterable 

695 promisc=None, # type: Optional[bool] 

696 filter=None, # type: Optional[str] 

697 nofilter=0, # type: int 

698 *args, # type: Any 

699 **kargs # type: Any 

700 ): 

701 # type: (...) -> Tuple[SndRcvList, PacketList] 

702 """ 

703 Send and receive packets at layer 3 

704 

705 This determines the interface (or L2 source to use) based on the routing 

706 table: conf.route / conf.route6 

707 """ 

708 if "iface" in kargs: 

709 # Warn that it isn't used. 

710 warnings.warn( 

711 "'iface' has no effect on L3 I/O sr(). For multicast/link-local " 

712 "see https://scapy.readthedocs.io/en/latest/usage.html#multicast", 

713 SyntaxWarning, 

714 ) 

715 del kargs["iface"] 

716 iface, ipv6 = _interface_selection(x) 

717 s = iface.l3socket(ipv6)( 

718 promisc=promisc, filter=filter, 

719 iface=iface, nofilter=nofilter, 

720 ) 

721 result = sndrcv(s, x, *args, **kargs) 

722 s.close() 

723 return result 

724 

725 

726@conf.commands.register 

727def sr1(*args, **kargs): 

728 # type: (*Any, **Any) -> Optional[Packet] 

729 """ 

730 Send packets at layer 3 and return only the first answer 

731 

732 This determines the interface (or L2 source to use) based on the routing 

733 table: conf.route / conf.route6 

734 """ 

735 if "iface" in kargs: 

736 # Warn that it isn't used. 

737 warnings.warn( 

738 "'iface' has no effect on L3 I/O sr1(). For multicast/link-local " 

739 "see https://scapy.readthedocs.io/en/latest/usage.html#multicast", 

740 SyntaxWarning, 

741 ) 

742 del kargs["iface"] 

743 ans, _ = sr(*args, **kargs) 

744 if ans: 

745 return cast(Packet, ans[0][1]) 

746 return None 

747 

748 

749@conf.commands.register 

750def srp(x, # type: _PacketIterable 

751 promisc=None, # type: Optional[bool] 

752 iface=None, # type: Optional[_GlobInterfaceType] 

753 iface_hint=None, # type: Optional[str] 

754 filter=None, # type: Optional[str] 

755 nofilter=0, # type: int 

756 type=ETH_P_ALL, # type: int 

757 *args, # type: Any 

758 **kargs # type: Any 

759 ): 

760 # type: (...) -> Tuple[SndRcvList, PacketList] 

761 """ 

762 Send and receive packets at layer 2 

763 """ 

764 if iface is None and iface_hint is not None: 

765 iface = conf.route.route(iface_hint)[0] 

766 iface = resolve_iface(iface or conf.iface) 

767 s = iface.l2socket()(promisc=promisc, iface=iface, 

768 filter=filter, nofilter=nofilter, type=type) 

769 result = sndrcv(s, x, *args, **kargs) 

770 s.close() 

771 return result 

772 

773 

774@conf.commands.register 

775def srp1(*args, **kargs): 

776 # type: (*Any, **Any) -> Optional[Packet] 

777 """ 

778 Send and receive packets at layer 2 and return only the first answer 

779 """ 

780 ans, _ = srp(*args, **kargs) 

781 if len(ans) > 0: 

782 return cast(Packet, ans[0][1]) 

783 return None 

784 

785 

786# Append doc 

787for sr_func in [srp, srp1, sr, sr1]: 

788 if sr_func.__doc__ is not None: 

789 sr_func.__doc__ += _DOC_SNDRCV_PARAMS 

790 

791 

792# SEND/RECV LOOP METHODS 

793 

794 

795def __sr_loop(srfunc, # type: Callable[..., Tuple[SndRcvList, PacketList]] 

796 pkts, # type: _PacketIterable 

797 prn=lambda x: x[1].summary(), # type: Optional[Callable[[QueryAnswer], Any]] # noqa: E501 

798 prnfail=lambda x: x.summary(), # type: Optional[Callable[[Packet], Any]] 

799 inter=1, # type: int 

800 timeout=None, # type: Optional[int] 

801 count=None, # type: Optional[int] 

802 verbose=None, # type: Optional[int] 

803 store=1, # type: int 

804 *args, # type: Any 

805 **kargs # type: Any 

806 ): 

807 # type: (...) -> Tuple[SndRcvList, PacketList] 

808 n = 0 

809 r = 0 

810 ct = conf.color_theme 

811 if verbose is None: 

812 verbose = conf.verb 

813 parity = 0 

814 ans = [] # type: List[QueryAnswer] 

815 unans = [] # type: List[Packet] 

816 if timeout is None: 

817 timeout = min(2 * inter, 5) 

818 try: 

819 while True: 

820 parity ^= 1 

821 col = [ct.even, ct.odd][parity] 

822 if count is not None: 

823 if count == 0: 

824 break 

825 count -= 1 

826 start = time.monotonic() 

827 if verbose > 1: 

828 print("\rsend...\r", end=' ') 

829 res = srfunc(pkts, timeout=timeout, verbose=0, chainCC=True, *args, **kargs) # noqa: E501 

830 n += len(res[0]) + len(res[1]) 

831 r += len(res[0]) 

832 if verbose > 1 and prn and len(res[0]) > 0: 

833 msg = "RECV %i:" % len(res[0]) 

834 print("\r" + ct.success(msg), end=' ') 

835 for rcv in res[0]: 

836 print(col(prn(rcv))) 

837 print(" " * len(msg), end=' ') 

838 if verbose > 1 and prnfail and len(res[1]) > 0: 

839 msg = "fail %i:" % len(res[1]) 

840 print("\r" + ct.fail(msg), end=' ') 

841 for fail in res[1]: 

842 print(col(prnfail(fail))) 

843 print(" " * len(msg), end=' ') 

844 if verbose > 1 and not (prn or prnfail): 

845 print("recv:%i fail:%i" % tuple( 

846 map(len, res[:2]) # type: ignore 

847 )) 

848 if verbose == 1: 

849 if res[0]: 

850 os.write(1, b"*") 

851 if res[1]: 

852 os.write(1, b".") 

853 if store: 

854 ans += res[0] 

855 unans += res[1] 

856 end = time.monotonic() 

857 if end - start < inter: 

858 time.sleep(inter + start - end) 

859 except KeyboardInterrupt: 

860 pass 

861 

862 if verbose and n > 0: 

863 print(ct.normal("\nSent %i packets, received %i packets. %3.1f%% hits." % (n, r, 100.0 * r / n))) # noqa: E501 

864 return SndRcvList(ans), PacketList(unans) 

865 

866 

867@conf.commands.register 

868def srloop(pkts, # type: _PacketIterable 

869 *args, # type: Any 

870 **kargs # type: Any 

871 ): 

872 # type: (...) -> Tuple[SndRcvList, PacketList] 

873 """ 

874 Send a packet at layer 3 in loop and print the answer each time 

875 srloop(pkts, [prn], [inter], [count], ...) --> None 

876 """ 

877 return __sr_loop(sr, pkts, *args, **kargs) 

878 

879 

880@conf.commands.register 

881def srploop(pkts, # type: _PacketIterable 

882 *args, # type: Any 

883 **kargs # type: Any 

884 ): 

885 # type: (...) -> Tuple[SndRcvList, PacketList] 

886 """ 

887 Send a packet at layer 2 in loop and print the answer each time 

888 srloop(pkts, [prn], [inter], [count], ...) --> None 

889 """ 

890 return __sr_loop(srp, pkts, *args, **kargs) 

891 

892# SEND/RECV FLOOD METHODS 

893 

894 

895class _FloodGenerator(object): 

896 def __init__(self, tobesent, maxretries): 

897 # type: (_PacketIterable, Optional[int]) -> None 

898 self.tobesent = tobesent 

899 self.maxretries = maxretries 

900 self.stopevent = Event() 

901 self.iterlen = 0 

902 

903 def __iter__(self): 

904 # type: () -> Iterator[Packet] 

905 i = 0 

906 while True: 

907 i += 1 

908 j = 0 

909 if self.maxretries and i >= self.maxretries: 

910 return 

911 for p in self.tobesent: 

912 if self.stopevent.is_set(): 

913 return 

914 j += 1 

915 yield p 

916 if self.iterlen == 0: 

917 self.iterlen = j 

918 

919 @property 

920 def sent_time(self): 

921 # type: () -> Union[EDecimal, float, None] 

922 return cast(Packet, self.tobesent).sent_time 

923 

924 @sent_time.setter 

925 def sent_time(self, val): 

926 # type: (Union[EDecimal, float, None]) -> None 

927 cast(Packet, self.tobesent).sent_time = val 

928 

929 def stop(self): 

930 # type: () -> None 

931 self.stopevent.set() 

932 

933 

934def sndrcvflood(pks, # type: SuperSocket 

935 pkt, # type: _PacketIterable 

936 inter=0, # type: int 

937 maxretries=None, # type: Optional[int] 

938 verbose=None, # type: Optional[int] 

939 chainCC=False, # type: bool 

940 timeout=None # type: Optional[int] 

941 ): 

942 # type: (...) -> Tuple[SndRcvList, PacketList] 

943 """sndrcv equivalent for flooding.""" 

944 

945 flood_gen = _FloodGenerator(pkt, maxretries) 

946 return sndrcv( 

947 pks, flood_gen, 

948 inter=inter, verbose=verbose, 

949 chainCC=chainCC, timeout=timeout, 

950 _flood=flood_gen 

951 ) 

952 

953 

954@conf.commands.register 

955def srflood(x, # type: _PacketIterable 

956 promisc=None, # type: Optional[bool] 

957 filter=None, # type: Optional[str] 

958 iface=None, # type: Optional[_GlobInterfaceType] 

959 nofilter=None, # type: Optional[bool] 

960 *args, # type: Any 

961 **kargs # type: Any 

962 ): 

963 # type: (...) -> Tuple[SndRcvList, PacketList] 

964 """Flood and receive packets at layer 3 

965 

966 This determines the interface (or L2 source to use) based on the routing 

967 table: conf.route / conf.route6 

968 

969 :param prn: function applied to packets received 

970 :param unique: only consider packets whose print 

971 :param nofilter: put 1 to avoid use of BPF filters 

972 :param filter: provide a BPF filter 

973 """ 

974 if "iface" in kargs: 

975 # Warn that it isn't used. 

976 warnings.warn( 

977 "'iface' has no effect on L3 I/O srflood(). For multicast/link-local " 

978 "see https://scapy.readthedocs.io/en/latest/usage.html#multicast", 

979 SyntaxWarning, 

980 ) 

981 del kargs["iface"] 

982 iface, ipv6 = _interface_selection(x) 

983 s = iface.l3socket(ipv6)( 

984 promisc=promisc, filter=filter, 

985 iface=iface, nofilter=nofilter, 

986 ) 

987 r = sndrcvflood(s, x, *args, **kargs) 

988 s.close() 

989 return r 

990 

991 

992@conf.commands.register 

993def sr1flood(x, # type: _PacketIterable 

994 promisc=None, # type: Optional[bool] 

995 filter=None, # type: Optional[str] 

996 nofilter=0, # type: int 

997 *args, # type: Any 

998 **kargs # type: Any 

999 ): 

1000 # type: (...) -> Optional[Packet] 

1001 """Flood and receive packets at layer 3 and return only the first answer 

1002 

1003 This determines the interface (or L2 source to use) based on the routing 

1004 table: conf.route / conf.route6 

1005 

1006 :param prn: function applied to packets received 

1007 :param verbose: set verbosity level 

1008 :param nofilter: put 1 to avoid use of BPF filters 

1009 :param filter: provide a BPF filter 

1010 :param iface: listen answers only on the given interface 

1011 """ 

1012 if "iface" in kargs: 

1013 # Warn that it isn't used. 

1014 warnings.warn( 

1015 "'iface' has no effect on L3 I/O sr1flood(). For multicast/link-local " 

1016 "see https://scapy.readthedocs.io/en/latest/usage.html#multicast", 

1017 SyntaxWarning, 

1018 ) 

1019 del kargs["iface"] 

1020 iface, ipv6 = _interface_selection(x) 

1021 s = iface.l3socket(ipv6)( 

1022 promisc=promisc, filter=filter, 

1023 nofilter=nofilter, iface=iface, 

1024 ) 

1025 ans, _ = sndrcvflood(s, x, *args, **kargs) 

1026 s.close() 

1027 if len(ans) > 0: 

1028 return cast(Packet, ans[0][1]) 

1029 return None 

1030 

1031 

1032@conf.commands.register 

1033def srpflood(x, # type: _PacketIterable 

1034 promisc=None, # type: Optional[bool] 

1035 filter=None, # type: Optional[str] 

1036 iface=None, # type: Optional[_GlobInterfaceType] 

1037 iface_hint=None, # type: Optional[str] 

1038 nofilter=None, # type: Optional[bool] 

1039 *args, # type: Any 

1040 **kargs # type: Any 

1041 ): 

1042 # type: (...) -> Tuple[SndRcvList, PacketList] 

1043 """Flood and receive packets at layer 2 

1044 

1045 :param prn: function applied to packets received 

1046 :param unique: only consider packets whose print 

1047 :param nofilter: put 1 to avoid use of BPF filters 

1048 :param filter: provide a BPF filter 

1049 :param iface: listen answers only on the given interface 

1050 """ 

1051 if iface is None and iface_hint is not None: 

1052 iface = conf.route.route(iface_hint)[0] 

1053 iface = resolve_iface(iface or conf.iface) 

1054 s = iface.l2socket()(promisc=promisc, filter=filter, iface=iface, nofilter=nofilter) # noqa: E501 

1055 r = sndrcvflood(s, x, *args, **kargs) 

1056 s.close() 

1057 return r 

1058 

1059 

1060@conf.commands.register 

1061def srp1flood(x, # type: _PacketIterable 

1062 promisc=None, # type: Optional[bool] 

1063 filter=None, # type: Optional[str] 

1064 iface=None, # type: Optional[_GlobInterfaceType] 

1065 nofilter=0, # type: int 

1066 *args, # type: Any 

1067 **kargs # type: Any 

1068 ): 

1069 # type: (...) -> Optional[Packet] 

1070 """Flood and receive packets at layer 2 and return only the first answer 

1071 

1072 :param prn: function applied to packets received 

1073 :param verbose: set verbosity level 

1074 :param nofilter: put 1 to avoid use of BPF filters 

1075 :param filter: provide a BPF filter 

1076 :param iface: listen answers only on the given interface 

1077 """ 

1078 iface = resolve_iface(iface or conf.iface) 

1079 s = iface.l2socket()(promisc=promisc, filter=filter, nofilter=nofilter, iface=iface) # noqa: E501 

1080 ans, _ = sndrcvflood(s, x, *args, **kargs) 

1081 s.close() 

1082 if len(ans) > 0: 

1083 return cast(Packet, ans[0][1]) 

1084 return None 

1085 

1086# SNIFF METHODS 

1087 

1088 

1089class AsyncSniffer(object): 

1090 """ 

1091 Sniff packets and return a list of packets. 

1092 

1093 Args: 

1094 count: number of packets to capture. 0 means infinity. 

1095 store: whether to store sniffed packets or discard them 

1096 prn: function to apply to each packet. If something is returned, it 

1097 is displayed. 

1098 --Ex: prn = lambda x: x.summary() 

1099 session: a session = a flow decoder used to handle stream of packets. 

1100 --Ex: session=TCPSession 

1101 See below for more details. 

1102 filter: BPF filter to apply. 

1103 lfilter: Python function applied to each packet to determine if 

1104 further action may be done. 

1105 --Ex: lfilter = lambda x: x.haslayer(Padding) 

1106 offline: PCAP file (or list of PCAP files) to read packets from, 

1107 instead of sniffing them 

1108 quiet: when set to True, the process stderr is discarded 

1109 (default: False). 

1110 timeout: stop sniffing after a given time (default: None). 

1111 L2socket: use the provided L2socket (default: use conf.L2listen). 

1112 opened_socket: provide an object (or a list of objects) ready to use 

1113 .recv() on. 

1114 stop_filter: Python function applied to each packet to determine if 

1115 we have to stop the capture after this packet. 

1116 --Ex: stop_filter = lambda x: x.haslayer(TCP) 

1117 iface: interface or list of interfaces (default: None for sniffing 

1118 on the default interface). 

1119 monitor: use monitor mode. May not be available on all OS 

1120 started_callback: called as soon as the sniffer starts sniffing 

1121 (default: None). 

1122 

1123 The iface, offline and opened_socket parameters can be either an 

1124 element, a list of elements, or a dict object mapping an element to a 

1125 label (see examples below). 

1126 

1127 For more information about the session argument, see 

1128 https://scapy.rtfd.io/en/latest/usage.html#advanced-sniffing-sniffing-sessions 

1129 

1130 Examples: synchronous 

1131 >>> sniff(filter="arp") 

1132 >>> sniff(filter="tcp", 

1133 ... session=IPSession, # defragment on-the-flow 

1134 ... prn=lambda x: x.summary()) 

1135 >>> sniff(lfilter=lambda pkt: ARP in pkt) 

1136 >>> sniff(iface="eth0", prn=Packet.summary) 

1137 >>> sniff(iface=["eth0", "mon0"], 

1138 ... prn=lambda pkt: "%s: %s" % (pkt.sniffed_on, 

1139 ... pkt.summary())) 

1140 >>> sniff(iface={"eth0": "Ethernet", "mon0": "Wifi"}, 

1141 ... prn=lambda pkt: "%s: %s" % (pkt.sniffed_on, 

1142 ... pkt.summary())) 

1143 

1144 Examples: asynchronous 

1145 >>> t = AsyncSniffer(iface="enp0s3") 

1146 >>> t.start() 

1147 >>> time.sleep(1) 

1148 >>> print("nice weather today") 

1149 >>> t.stop() 

1150 """ 

1151 

1152 def __init__(self, *args, **kwargs): 

1153 # type: (*Any, **Any) -> None 

1154 # Store keyword arguments 

1155 self.args = args 

1156 self.kwargs = kwargs 

1157 self.running = False 

1158 self.thread = None # type: Optional[Thread] 

1159 self.results = None # type: Optional[PacketList] 

1160 self.exception = None # type: Optional[Exception] 

1161 self.stop_cb = lambda: None # type: Callable[[], None] 

1162 

1163 def _setup_thread(self): 

1164 # type: () -> None 

1165 def _run_catch(self=self, *args, **kwargs): 

1166 # type: (Any, *Any, **Any) -> None 

1167 try: 

1168 self._run(*args, **kwargs) 

1169 except Exception as ex: 

1170 self.exception = ex 

1171 # Prepare sniffing thread 

1172 self.thread = Thread( 

1173 target=_run_catch, 

1174 args=self.args, 

1175 kwargs=self.kwargs, 

1176 name="AsyncSniffer" 

1177 ) 

1178 self.thread.daemon = True 

1179 

1180 def _run(self, 

1181 count=0, # type: int 

1182 store=True, # type: bool 

1183 offline=None, # type: Any 

1184 quiet=False, # type: bool 

1185 prn=None, # type: Optional[Callable[[Packet], Any]] 

1186 lfilter=None, # type: Optional[Callable[[Packet], bool]] 

1187 L2socket=None, # type: Optional[Type[SuperSocket]] 

1188 timeout=None, # type: Optional[int] 

1189 opened_socket=None, # type: Optional[SuperSocket] 

1190 stop_filter=None, # type: Optional[Callable[[Packet], bool]] 

1191 iface=None, # type: Optional[_GlobInterfaceType] 

1192 started_callback=None, # type: Optional[Callable[[], Any]] 

1193 session=None, # type: Optional[_GlobSessionType] 

1194 chainCC=False, # type: bool 

1195 **karg # type: Any 

1196 ): 

1197 # type: (...) -> None 

1198 self.running = True 

1199 self.count = 0 

1200 lst = [] 

1201 # Start main thread 

1202 # instantiate session 

1203 if not isinstance(session, DefaultSession): 

1204 session = session or DefaultSession 

1205 session = session() 

1206 # sniff_sockets follows: {socket: label} 

1207 sniff_sockets = {} # type: Dict[SuperSocket, _GlobInterfaceType] 

1208 if opened_socket is not None: 

1209 if isinstance(opened_socket, list): 

1210 sniff_sockets.update( 

1211 (s, "socket%d" % i) 

1212 for i, s in enumerate(opened_socket) 

1213 ) 

1214 elif isinstance(opened_socket, dict): 

1215 sniff_sockets.update( 

1216 (s, label) 

1217 for s, label in opened_socket.items() 

1218 ) 

1219 else: 

1220 sniff_sockets[opened_socket] = "socket0" 

1221 if offline is not None: 

1222 flt = karg.get('filter') 

1223 

1224 if isinstance(offline, str): 

1225 # Single file 

1226 offline = [offline] 

1227 if isinstance(offline, list) and \ 

1228 all(isinstance(elt, str) for elt in offline): 

1229 # List of files 

1230 sniff_sockets.update((PcapReader( # type: ignore 

1231 fname if flt is None else 

1232 tcpdump(fname, 

1233 args=["-w", "-"], 

1234 flt=flt, 

1235 getfd=True, 

1236 quiet=quiet) 

1237 ), fname) for fname in offline) 

1238 elif isinstance(offline, dict): 

1239 # Dict of files 

1240 sniff_sockets.update((PcapReader( # type: ignore 

1241 fname if flt is None else 

1242 tcpdump(fname, 

1243 args=["-w", "-"], 

1244 flt=flt, 

1245 getfd=True, 

1246 quiet=quiet) 

1247 ), label) for fname, label in offline.items()) 

1248 elif isinstance(offline, (Packet, PacketList, list)): 

1249 # Iterables (list of packets, PacketList..) 

1250 offline = IterSocket(offline) 

1251 sniff_sockets[offline if flt is None else PcapReader( 

1252 tcpdump(offline, 

1253 args=["-w", "-"], 

1254 flt=flt, 

1255 getfd=True, 

1256 quiet=quiet) 

1257 )] = offline 

1258 else: 

1259 # Other (file descriptors...) 

1260 sniff_sockets[PcapReader( # type: ignore 

1261 offline if flt is None else 

1262 tcpdump(offline, 

1263 args=["-w", "-"], 

1264 flt=flt, 

1265 getfd=True, 

1266 quiet=quiet) 

1267 )] = offline 

1268 if not sniff_sockets or iface is not None: 

1269 # The _RL2 function resolves the L2socket of an iface 

1270 _RL2 = lambda i: L2socket or resolve_iface(i).l2listen() # type: Callable[[_GlobInterfaceType], Callable[..., SuperSocket]] # noqa: E501 

1271 if isinstance(iface, list): 

1272 sniff_sockets.update( 

1273 (_RL2(ifname)(type=ETH_P_ALL, iface=ifname, **karg), 

1274 ifname) 

1275 for ifname in iface 

1276 ) 

1277 elif isinstance(iface, dict): 

1278 sniff_sockets.update( 

1279 (_RL2(ifname)(type=ETH_P_ALL, iface=ifname, **karg), 

1280 iflabel) 

1281 for ifname, iflabel in iface.items() 

1282 ) 

1283 else: 

1284 iface = iface or conf.iface 

1285 sniff_sockets[_RL2(iface)(type=ETH_P_ALL, iface=iface, 

1286 **karg)] = iface 

1287 

1288 # Get select information from the sockets 

1289 _main_socket = next(iter(sniff_sockets)) 

1290 select_func = _main_socket.select 

1291 nonblocking_socket = getattr(_main_socket, "nonblocking_socket", False) 

1292 # We check that all sockets use the same select(), or raise a warning 

1293 if not all(select_func == sock.select for sock in sniff_sockets): 

1294 warning("Warning: inconsistent socket types ! " 

1295 "The used select function " 

1296 "will be the one of the first socket") 

1297 

1298 close_pipe = None # type: Optional[ObjectPipe[None]] 

1299 if not nonblocking_socket: 

1300 # select is blocking: Add special control socket 

1301 from scapy.automaton import ObjectPipe 

1302 close_pipe = ObjectPipe[None]("control_socket") 

1303 sniff_sockets[close_pipe] = "control_socket" # type: ignore 

1304 

1305 def stop_cb(): 

1306 # type: () -> None 

1307 if self.running and close_pipe: 

1308 close_pipe.send(None) 

1309 self.continue_sniff = False 

1310 self.stop_cb = stop_cb 

1311 else: 

1312 # select is non blocking 

1313 def stop_cb(): 

1314 # type: () -> None 

1315 self.continue_sniff = False 

1316 self.stop_cb = stop_cb 

1317 

1318 try: 

1319 self.continue_sniff = True 

1320 if started_callback: 

1321 started_callback() 

1322 

1323 # Start timeout 

1324 if timeout is not None: 

1325 stoptime = time.monotonic() + timeout 

1326 remain = None 

1327 

1328 while sniff_sockets and self.continue_sniff: 

1329 if timeout is not None: 

1330 remain = stoptime - time.monotonic() 

1331 if remain <= 0: 

1332 break 

1333 sockets = select_func(list(sniff_sockets.keys()), remain) 

1334 dead_sockets = [] 

1335 for s in sockets: 

1336 if s is close_pipe: # type: ignore 

1337 break 

1338 # The session object is passed the socket to call recv() on, 

1339 # and may perform additional processing (ip defrag, etc.) 

1340 try: 

1341 packets = session.recv(s) 

1342 # A session can return multiple objects 

1343 for p in packets: 

1344 if lfilter and not lfilter(p): 

1345 continue 

1346 p.sniffed_on = sniff_sockets.get(s, None) 

1347 # post-processing 

1348 self.count += 1 

1349 if store: 

1350 lst.append(p) 

1351 if prn: 

1352 result = prn(p) 

1353 if result is not None: 

1354 print(result) 

1355 # check 

1356 if (stop_filter and stop_filter(p)) or \ 

1357 (0 < count <= self.count): 

1358 self.continue_sniff = False 

1359 break 

1360 except EOFError: 

1361 # End of stream 

1362 try: 

1363 s.close() 

1364 except Exception: 

1365 pass 

1366 dead_sockets.append(s) 

1367 continue 

1368 except Exception as ex: 

1369 msg = " It was closed." 

1370 try: 

1371 # Make sure it's closed 

1372 s.close() 

1373 except Exception as ex2: 

1374 msg = " close() failed with '%s'" % ex2 

1375 warning( 

1376 "Socket %s failed with '%s'." % (s, ex) + msg 

1377 ) 

1378 dead_sockets.append(s) 

1379 if conf.debug_dissector >= 2: 

1380 raise 

1381 continue 

1382 # Removed dead sockets 

1383 for s in dead_sockets: 

1384 del sniff_sockets[s] 

1385 if len(sniff_sockets) == 1 and \ 

1386 close_pipe in sniff_sockets: # type: ignore 

1387 # Only the close_pipe left 

1388 del sniff_sockets[close_pipe] # type: ignore 

1389 except KeyboardInterrupt: 

1390 if chainCC: 

1391 raise 

1392 self.running = False 

1393 if opened_socket is None: 

1394 for s in sniff_sockets: 

1395 s.close() 

1396 elif close_pipe: 

1397 close_pipe.close() 

1398 self.results = PacketList(lst, "Sniffed") 

1399 

1400 def start(self): 

1401 # type: () -> None 

1402 """Starts AsyncSniffer in async mode""" 

1403 self._setup_thread() 

1404 if self.thread: 

1405 self.thread.start() 

1406 

1407 def stop(self, join=True): 

1408 # type: (bool) -> Optional[PacketList] 

1409 """Stops AsyncSniffer if not in async mode""" 

1410 if self.running: 

1411 self.stop_cb() 

1412 if not hasattr(self, "continue_sniff"): 

1413 # Never started -> is there an exception? 

1414 if self.exception is not None: 

1415 raise self.exception 

1416 return None 

1417 if self.continue_sniff: 

1418 raise Scapy_Exception( 

1419 "Unsupported (offline or unsupported socket)" 

1420 ) 

1421 if join: 

1422 self.join() 

1423 return self.results 

1424 return None 

1425 else: 

1426 raise Scapy_Exception("Not running ! (check .running attr)") 

1427 

1428 def join(self, *args, **kwargs): 

1429 # type: (*Any, **Any) -> None 

1430 if self.thread: 

1431 self.thread.join(*args, **kwargs) 

1432 if self.exception is not None: 

1433 raise self.exception 

1434 

1435 

1436@conf.commands.register 

1437def sniff(*args, **kwargs): 

1438 # type: (*Any, **Any) -> PacketList 

1439 sniffer = AsyncSniffer() 

1440 sniffer._run(*args, **kwargs) 

1441 return cast(PacketList, sniffer.results) 

1442 

1443 

1444sniff.__doc__ = AsyncSniffer.__doc__ 

1445 

1446 

1447@conf.commands.register 

1448def bridge_and_sniff(if1, # type: _GlobInterfaceType 

1449 if2, # type: _GlobInterfaceType 

1450 xfrm12=None, # type: Optional[Callable[[Packet], Union[Packet, bool]]] # noqa: E501 

1451 xfrm21=None, # type: Optional[Callable[[Packet], Union[Packet, bool]]] # noqa: E501 

1452 prn=None, # type: Optional[Callable[[Packet], Any]] 

1453 L2socket=None, # type: Optional[Type[SuperSocket]] 

1454 *args, # type: Any 

1455 **kargs # type: Any 

1456 ): 

1457 # type: (...) -> PacketList 

1458 """Forward traffic between interfaces if1 and if2, sniff and return 

1459 the exchanged packets. 

1460 

1461 :param if1: the interfaces to use (interface names or opened sockets). 

1462 :param if2: 

1463 :param xfrm12: a function to call when forwarding a packet from if1 to 

1464 if2. If it returns True, the packet is forwarded as it. If it 

1465 returns False or None, the packet is discarded. If it returns a 

1466 packet, this packet is forwarded instead of the original packet 

1467 one. 

1468 :param xfrm21: same as xfrm12 for packets forwarded from if2 to if1. 

1469 

1470 The other arguments are the same than for the function sniff(), 

1471 except for offline, opened_socket and iface that are ignored. 

1472 See help(sniff) for more. 

1473 """ 

1474 for arg in ['opened_socket', 'offline', 'iface']: 

1475 if arg in kargs: 

1476 log_runtime.warning("Argument %s cannot be used in " 

1477 "bridge_and_sniff() -- ignoring it.", arg) 

1478 del kargs[arg] 

1479 

1480 def _init_socket(iface, # type: _GlobInterfaceType 

1481 count, # type: int 

1482 L2socket=L2socket # type: Optional[Type[SuperSocket]] 

1483 ): 

1484 # type: (...) -> Tuple[SuperSocket, _GlobInterfaceType] 

1485 if isinstance(iface, SuperSocket): 

1486 return iface, "iface%d" % count 

1487 else: 

1488 if not L2socket: 

1489 iface = resolve_iface(iface or conf.iface) 

1490 L2socket = iface.l2socket() 

1491 return L2socket(iface=iface), iface 

1492 sckt1, if1 = _init_socket(if1, 1) 

1493 sckt2, if2 = _init_socket(if2, 2) 

1494 peers = {if1: sckt2, if2: sckt1} 

1495 xfrms = {} 

1496 if xfrm12 is not None: 

1497 xfrms[if1] = xfrm12 

1498 if xfrm21 is not None: 

1499 xfrms[if2] = xfrm21 

1500 

1501 def prn_send(pkt): 

1502 # type: (Packet) -> None 

1503 try: 

1504 sendsock = peers[pkt.sniffed_on or ""] 

1505 except KeyError: 

1506 return 

1507 if pkt.sniffed_on in xfrms: 

1508 try: 

1509 _newpkt = xfrms[pkt.sniffed_on](pkt) 

1510 except Exception: 

1511 log_runtime.warning( 

1512 'Exception in transformation function for packet [%s] ' 

1513 'received on %s -- dropping', 

1514 pkt.summary(), pkt.sniffed_on, exc_info=True 

1515 ) 

1516 return 

1517 else: 

1518 if isinstance(_newpkt, bool): 

1519 if not _newpkt: 

1520 return 

1521 newpkt = pkt 

1522 else: 

1523 newpkt = _newpkt 

1524 else: 

1525 newpkt = pkt 

1526 try: 

1527 sendsock.send(newpkt) 

1528 except Exception: 

1529 log_runtime.warning('Cannot forward packet [%s] received on %s', 

1530 pkt.summary(), pkt.sniffed_on, exc_info=True) 

1531 if prn is None: 

1532 prn = prn_send 

1533 else: 

1534 prn_orig = prn 

1535 

1536 def prn(pkt): 

1537 # type: (Packet) -> Any 

1538 prn_send(pkt) 

1539 return prn_orig(pkt) 

1540 

1541 return sniff(opened_socket={sckt1: if1, sckt2: if2}, prn=prn, 

1542 *args, **kargs) 

1543 

1544 

1545@conf.commands.register 

1546def tshark(*args, **kargs): 

1547 # type: (Any, Any) -> None 

1548 """Sniff packets and print them calling pkt.summary(). 

1549 This tries to replicate what text-wireshark (tshark) would look like""" 

1550 

1551 if 'iface' in kargs: 

1552 iface = kargs.get('iface') 

1553 elif 'opened_socket' in kargs: 

1554 iface = cast(SuperSocket, kargs.get('opened_socket')).iface 

1555 else: 

1556 iface = conf.iface 

1557 print("Capturing on '%s'" % iface) 

1558 

1559 # This should be a nonlocal variable, using a mutable object 

1560 # for Python 2 compatibility 

1561 i = [0] 

1562 

1563 def _cb(pkt): 

1564 # type: (Packet) -> None 

1565 print("%5d\t%s" % (i[0], pkt.summary())) 

1566 i[0] += 1 

1567 

1568 sniff(prn=_cb, store=False, *args, **kargs) 

1569 print("\n%d packet%s captured" % (i[0], 's' if i[0] > 1 else ''))