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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

730 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 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 cmd.wait() 

589 except KeyboardInterrupt: 

590 if cmd: 

591 cmd.terminate() 

592 log_interactive.info("Interrupted by user") 

593 except Exception: 

594 os.unlink(f) 

595 raise 

596 finally: 

597 stdout, stderr = cmd.communicate() 

598 if stderr: 

599 log_runtime.warning(stderr.decode()) 

600 if parse_results: 

601 results = _parse_tcpreplay_result(stdout, stderr, argv) 

602 elif conf.verb > 2: 

603 log_runtime.info(stdout.decode()) 

604 if os.path.exists(f): 

605 os.unlink(f) 

606 return results 

607 

608 

609def _parse_tcpreplay_result(stdout_b, stderr_b, argv): 

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

611 """ 

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

613 Tested with tcpreplay v3.4.4 

614 Tested with tcpreplay v4.1.2 

615 :param stdout: stdout of tcpreplay subprocess call 

616 :param stderr: stderr of tcpreplay subprocess call 

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

618 :return: dictionary containing the results 

619 """ 

620 try: 

621 results = {} 

622 stdout = plain_str(stdout_b).lower() 

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

624 elements = { 

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

626 "rated": (float, float, float), 

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

628 "attempted": (int,), 

629 "successful": (int,), 

630 "failed": (int,), 

631 "truncated": (int,), 

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

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

634 } 

635 multi = { 

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

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

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

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

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

641 } 

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

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

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

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

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

647 line = line.strip() 

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

649 if line.startswith(elt): 

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

651 matches = re.search(regex, line) 

652 for i, typ in enumerate(_types): 

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

654 if matches: 

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

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

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

658 return results 

659 except Exception as parse_exception: 

660 if not conf.interactive: 

661 raise 

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

663 return {} 

664 

665 

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

667 """ 

668 Select the network interface according to the layer 3 destination 

669 """ 

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

671 ipv6 = False 

672 if src: 

673 try: 

674 inet_pton(socket.AF_INET6, src) 

675 ipv6 = True 

676 except (ValueError, OSError): 

677 pass 

678 try: 

679 iff = resolve_iface(_iff or conf.iface) 

680 except AttributeError: 

681 iff = None 

682 return iff or conf.iface, ipv6 

683 

684 

685@conf.commands.register 

686def sr(x, # type: _PacketIterable 

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

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

689 nofilter=0, # type: int 

690 *args, # type: Any 

691 **kargs # type: Any 

692 ): 

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

694 """ 

695 Send and receive packets at layer 3 

696 

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

698 table: conf.route / conf.route6 

699 """ 

700 if "iface" in kargs: 

701 # Warn that it isn't used. 

702 warnings.warn( 

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

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

705 SyntaxWarning, 

706 ) 

707 del kargs["iface"] 

708 iface, ipv6 = _interface_selection(x) 

709 s = iface.l3socket(ipv6)( 

710 promisc=promisc, filter=filter, 

711 iface=iface, nofilter=nofilter, 

712 ) 

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

714 s.close() 

715 return result 

716 

717 

718@conf.commands.register 

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

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

721 """ 

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

723 

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

725 table: conf.route / conf.route6 

726 """ 

727 if "iface" in kargs: 

728 # Warn that it isn't used. 

729 warnings.warn( 

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

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

732 SyntaxWarning, 

733 ) 

734 del kargs["iface"] 

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

736 if ans: 

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

738 return None 

739 

740 

741@conf.commands.register 

742def srp(x, # type: _PacketIterable 

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

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

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

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

747 nofilter=0, # type: int 

748 type=ETH_P_ALL, # type: int 

749 *args, # type: Any 

750 **kargs # type: Any 

751 ): 

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

753 """ 

754 Send and receive packets at layer 2 

755 """ 

756 if iface is None and iface_hint is not None: 

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

758 iface = resolve_iface(iface or conf.iface) 

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

760 filter=filter, nofilter=nofilter, type=type) 

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

762 s.close() 

763 return result 

764 

765 

766@conf.commands.register 

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

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

769 """ 

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

771 """ 

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

773 if len(ans) > 0: 

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

775 return None 

776 

777 

778# Append doc 

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

780 if sr_func.__doc__ is not None: 

781 sr_func.__doc__ += _DOC_SNDRCV_PARAMS 

782 

783 

784# SEND/RECV LOOP METHODS 

785 

786 

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

788 pkts, # type: _PacketIterable 

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

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

791 inter=1, # type: int 

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

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

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

795 store=1, # type: int 

796 *args, # type: Any 

797 **kargs # type: Any 

798 ): 

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

800 n = 0 

801 r = 0 

802 ct = conf.color_theme 

803 if verbose is None: 

804 verbose = conf.verb 

805 parity = 0 

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

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

808 if timeout is None: 

809 timeout = min(2 * inter, 5) 

810 try: 

811 while True: 

812 parity ^= 1 

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

814 if count is not None: 

815 if count == 0: 

816 break 

817 count -= 1 

818 start = time.monotonic() 

819 if verbose > 1: 

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

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

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

823 r += len(res[0]) 

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

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

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

827 for rcv in res[0]: 

828 print(col(prn(rcv))) 

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

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

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

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

833 for fail in res[1]: 

834 print(col(prnfail(fail))) 

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

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

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

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

839 )) 

840 if verbose == 1: 

841 if res[0]: 

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

843 if res[1]: 

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

845 if store: 

846 ans += res[0] 

847 unans += res[1] 

848 end = time.monotonic() 

849 if end - start < inter: 

850 time.sleep(inter + start - end) 

851 except KeyboardInterrupt: 

852 pass 

853 

854 if verbose and n > 0: 

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

856 return SndRcvList(ans), PacketList(unans) 

857 

858 

859@conf.commands.register 

860def srloop(pkts, # type: _PacketIterable 

861 *args, # type: Any 

862 **kargs # type: Any 

863 ): 

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

865 """ 

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

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

868 """ 

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

870 

871 

872@conf.commands.register 

873def srploop(pkts, # type: _PacketIterable 

874 *args, # type: Any 

875 **kargs # type: Any 

876 ): 

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

878 """ 

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

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

881 """ 

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

883 

884# SEND/RECV FLOOD METHODS 

885 

886 

887class _FloodGenerator(object): 

888 def __init__(self, tobesent, maxretries): 

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

890 self.tobesent = tobesent 

891 self.maxretries = maxretries 

892 self.stopevent = Event() 

893 self.iterlen = 0 

894 

895 def __iter__(self): 

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

897 i = 0 

898 while True: 

899 i += 1 

900 j = 0 

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

902 return 

903 for p in self.tobesent: 

904 if self.stopevent.is_set(): 

905 return 

906 j += 1 

907 yield p 

908 if self.iterlen == 0: 

909 self.iterlen = j 

910 

911 @property 

912 def sent_time(self): 

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

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

915 

916 @sent_time.setter 

917 def sent_time(self, val): 

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

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

920 

921 def stop(self): 

922 # type: () -> None 

923 self.stopevent.set() 

924 

925 

926def sndrcvflood(pks, # type: SuperSocket 

927 pkt, # type: _PacketIterable 

928 inter=0, # type: int 

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

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

931 chainCC=False, # type: bool 

932 timeout=None # type: Optional[int] 

933 ): 

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

935 """sndrcv equivalent for flooding.""" 

936 

937 flood_gen = _FloodGenerator(pkt, maxretries) 

938 return sndrcv( 

939 pks, flood_gen, 

940 inter=inter, verbose=verbose, 

941 chainCC=chainCC, timeout=timeout, 

942 _flood=flood_gen 

943 ) 

944 

945 

946@conf.commands.register 

947def srflood(x, # type: _PacketIterable 

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

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

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

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

952 *args, # type: Any 

953 **kargs # type: Any 

954 ): 

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

956 """Flood and receive packets at layer 3 

957 

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

959 table: conf.route / conf.route6 

960 

961 :param prn: function applied to packets received 

962 :param unique: only consider packets whose print 

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

964 :param filter: provide a BPF filter 

965 """ 

966 if "iface" in kargs: 

967 # Warn that it isn't used. 

968 warnings.warn( 

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

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

971 SyntaxWarning, 

972 ) 

973 del kargs["iface"] 

974 iface, ipv6 = _interface_selection(x) 

975 s = iface.l3socket(ipv6)( 

976 promisc=promisc, filter=filter, 

977 iface=iface, nofilter=nofilter, 

978 ) 

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

980 s.close() 

981 return r 

982 

983 

984@conf.commands.register 

985def sr1flood(x, # type: _PacketIterable 

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

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

988 nofilter=0, # type: int 

989 *args, # type: Any 

990 **kargs # type: Any 

991 ): 

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

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

994 

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

996 table: conf.route / conf.route6 

997 

998 :param prn: function applied to packets received 

999 :param verbose: set verbosity level 

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

1001 :param filter: provide a BPF filter 

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

1003 """ 

1004 if "iface" in kargs: 

1005 # Warn that it isn't used. 

1006 warnings.warn( 

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

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

1009 SyntaxWarning, 

1010 ) 

1011 del kargs["iface"] 

1012 iface, ipv6 = _interface_selection(x) 

1013 s = iface.l3socket(ipv6)( 

1014 promisc=promisc, filter=filter, 

1015 nofilter=nofilter, iface=iface, 

1016 ) 

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

1018 s.close() 

1019 if len(ans) > 0: 

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

1021 return None 

1022 

1023 

1024@conf.commands.register 

1025def srpflood(x, # type: _PacketIterable 

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

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

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

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

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

1031 *args, # type: Any 

1032 **kargs # type: Any 

1033 ): 

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

1035 """Flood and receive packets at layer 2 

1036 

1037 :param prn: function applied to packets received 

1038 :param unique: only consider packets whose print 

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

1040 :param filter: provide a BPF filter 

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

1042 """ 

1043 if iface is None and iface_hint is not None: 

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

1045 iface = resolve_iface(iface or conf.iface) 

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

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

1048 s.close() 

1049 return r 

1050 

1051 

1052@conf.commands.register 

1053def srp1flood(x, # type: _PacketIterable 

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

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

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

1057 nofilter=0, # type: int 

1058 *args, # type: Any 

1059 **kargs # type: Any 

1060 ): 

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

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

1063 

1064 :param prn: function applied to packets received 

1065 :param verbose: set verbosity level 

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

1067 :param filter: provide a BPF filter 

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

1069 """ 

1070 iface = resolve_iface(iface or conf.iface) 

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

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

1073 s.close() 

1074 if len(ans) > 0: 

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

1076 return None 

1077 

1078# SNIFF METHODS 

1079 

1080 

1081class AsyncSniffer(object): 

1082 """ 

1083 Sniff packets and return a list of packets. 

1084 

1085 Args: 

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

1087 store: whether to store sniffed packets or discard them 

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

1089 is displayed. 

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

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

1092 --Ex: session=TCPSession 

1093 See below for more details. 

1094 filter: BPF filter to apply. 

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

1096 further action may be done. 

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

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

1099 instead of sniffing them 

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

1101 (default: False). 

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

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

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

1105 .recv() on. 

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

1107 we have to stop the capture after this packet. 

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

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

1110 on the default interface). 

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

1112 started_callback: called as soon as the sniffer starts sniffing 

1113 (default: None). 

1114 

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

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

1117 label (see examples below). 

1118 

1119 For more information about the session argument, see 

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

1121 

1122 Examples: synchronous 

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

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

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

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

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

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

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

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

1131 ... pkt.summary())) 

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

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

1134 ... pkt.summary())) 

1135 

1136 Examples: asynchronous 

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

1138 >>> t.start() 

1139 >>> time.sleep(1) 

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

1141 >>> t.stop() 

1142 """ 

1143 

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

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

1146 # Store keyword arguments 

1147 self.args = args 

1148 self.kwargs = kwargs 

1149 self.running = False 

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

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

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

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

1154 

1155 def _setup_thread(self): 

1156 # type: () -> None 

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

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

1159 try: 

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

1161 except Exception as ex: 

1162 self.exception = ex 

1163 # Prepare sniffing thread 

1164 self.thread = Thread( 

1165 target=_run_catch, 

1166 args=self.args, 

1167 kwargs=self.kwargs, 

1168 name="AsyncSniffer" 

1169 ) 

1170 self.thread.daemon = True 

1171 

1172 def _run(self, 

1173 count=0, # type: int 

1174 store=True, # type: bool 

1175 offline=None, # type: Any 

1176 quiet=False, # type: bool 

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

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

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

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

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

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

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

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

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

1186 chainCC=False, # type: bool 

1187 **karg # type: Any 

1188 ): 

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

1190 self.running = True 

1191 self.count = 0 

1192 lst = [] 

1193 # Start main thread 

1194 # instantiate session 

1195 if not isinstance(session, DefaultSession): 

1196 session = session or DefaultSession 

1197 session = session() 

1198 # sniff_sockets follows: {socket: label} 

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

1200 if opened_socket is not None: 

1201 if isinstance(opened_socket, list): 

1202 sniff_sockets.update( 

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

1204 for i, s in enumerate(opened_socket) 

1205 ) 

1206 elif isinstance(opened_socket, dict): 

1207 sniff_sockets.update( 

1208 (s, label) 

1209 for s, label in opened_socket.items() 

1210 ) 

1211 else: 

1212 sniff_sockets[opened_socket] = "socket0" 

1213 if offline is not None: 

1214 flt = karg.get('filter') 

1215 

1216 if isinstance(offline, str): 

1217 # Single file 

1218 offline = [offline] 

1219 if isinstance(offline, list) and \ 

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

1221 # List of files 

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

1223 fname if flt is None else 

1224 tcpdump(fname, 

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

1226 flt=flt, 

1227 getfd=True, 

1228 quiet=quiet) 

1229 ), fname) for fname in offline) 

1230 elif isinstance(offline, dict): 

1231 # Dict of files 

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

1233 fname if flt is None else 

1234 tcpdump(fname, 

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

1236 flt=flt, 

1237 getfd=True, 

1238 quiet=quiet) 

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

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

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

1242 offline = IterSocket(offline) 

1243 sniff_sockets[offline if flt is None else PcapReader( 

1244 tcpdump(offline, 

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

1246 flt=flt, 

1247 getfd=True, 

1248 quiet=quiet) 

1249 )] = offline 

1250 else: 

1251 # Other (file descriptors...) 

1252 sniff_sockets[PcapReader( # type: ignore 

1253 offline if flt is None else 

1254 tcpdump(offline, 

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

1256 flt=flt, 

1257 getfd=True, 

1258 quiet=quiet) 

1259 )] = offline 

1260 if not sniff_sockets or iface is not None: 

1261 # The _RL2 function resolves the L2socket of an iface 

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

1263 if isinstance(iface, list): 

1264 sniff_sockets.update( 

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

1266 ifname) 

1267 for ifname in iface 

1268 ) 

1269 elif isinstance(iface, dict): 

1270 sniff_sockets.update( 

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

1272 iflabel) 

1273 for ifname, iflabel in iface.items() 

1274 ) 

1275 else: 

1276 iface = iface or conf.iface 

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

1278 **karg)] = iface 

1279 

1280 # Get select information from the sockets 

1281 _main_socket = next(iter(sniff_sockets)) 

1282 select_func = _main_socket.select 

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

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

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

1286 warning("Warning: inconsistent socket types ! " 

1287 "The used select function " 

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

1289 

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

1291 if not nonblocking_socket: 

1292 # select is blocking: Add special control socket 

1293 from scapy.automaton import ObjectPipe 

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

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

1296 

1297 def stop_cb(): 

1298 # type: () -> None 

1299 if self.running and close_pipe: 

1300 close_pipe.send(None) 

1301 self.continue_sniff = False 

1302 self.stop_cb = stop_cb 

1303 else: 

1304 # select is non blocking 

1305 def stop_cb(): 

1306 # type: () -> None 

1307 self.continue_sniff = False 

1308 self.stop_cb = stop_cb 

1309 

1310 try: 

1311 if started_callback: 

1312 started_callback() 

1313 self.continue_sniff = True 

1314 

1315 # Start timeout 

1316 if timeout is not None: 

1317 stoptime = time.monotonic() + timeout 

1318 remain = None 

1319 

1320 while sniff_sockets and self.continue_sniff: 

1321 if timeout is not None: 

1322 remain = stoptime - time.monotonic() 

1323 if remain <= 0: 

1324 break 

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

1326 dead_sockets = [] 

1327 for s in sockets: 

1328 if s is close_pipe: # type: ignore 

1329 break 

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

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

1332 try: 

1333 packets = session.recv(s) 

1334 # A session can return multiple objects 

1335 for p in packets: 

1336 if lfilter and not lfilter(p): 

1337 continue 

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

1339 # post-processing 

1340 self.count += 1 

1341 if store: 

1342 lst.append(p) 

1343 if prn: 

1344 result = prn(p) 

1345 if result is not None: 

1346 print(result) 

1347 # check 

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

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

1350 self.continue_sniff = False 

1351 break 

1352 except EOFError: 

1353 # End of stream 

1354 try: 

1355 s.close() 

1356 except Exception: 

1357 pass 

1358 dead_sockets.append(s) 

1359 continue 

1360 except Exception as ex: 

1361 msg = " It was closed." 

1362 try: 

1363 # Make sure it's closed 

1364 s.close() 

1365 except Exception as ex2: 

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

1367 warning( 

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

1369 ) 

1370 dead_sockets.append(s) 

1371 if conf.debug_dissector >= 2: 

1372 raise 

1373 continue 

1374 # Removed dead sockets 

1375 for s in dead_sockets: 

1376 del sniff_sockets[s] 

1377 if len(sniff_sockets) == 1 and \ 

1378 close_pipe in sniff_sockets: # type: ignore 

1379 # Only the close_pipe left 

1380 del sniff_sockets[close_pipe] # type: ignore 

1381 except KeyboardInterrupt: 

1382 if chainCC: 

1383 raise 

1384 self.running = False 

1385 if opened_socket is None: 

1386 for s in sniff_sockets: 

1387 s.close() 

1388 elif close_pipe: 

1389 close_pipe.close() 

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

1391 

1392 def start(self): 

1393 # type: () -> None 

1394 """Starts AsyncSniffer in async mode""" 

1395 self._setup_thread() 

1396 if self.thread: 

1397 self.thread.start() 

1398 

1399 def stop(self, join=True): 

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

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

1402 if self.running: 

1403 try: 

1404 self.stop_cb() 

1405 except AttributeError: 

1406 raise Scapy_Exception( 

1407 "Unsupported (offline or unsupported socket)" 

1408 ) 

1409 if join: 

1410 self.join() 

1411 return self.results 

1412 return None 

1413 else: 

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

1415 

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

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

1418 if self.thread: 

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

1420 if self.exception is not None: 

1421 raise self.exception 

1422 

1423 

1424@conf.commands.register 

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

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

1427 sniffer = AsyncSniffer() 

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

1429 return cast(PacketList, sniffer.results) 

1430 

1431 

1432sniff.__doc__ = AsyncSniffer.__doc__ 

1433 

1434 

1435@conf.commands.register 

1436def bridge_and_sniff(if1, # type: _GlobInterfaceType 

1437 if2, # type: _GlobInterfaceType 

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

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

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

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

1442 *args, # type: Any 

1443 **kargs # type: Any 

1444 ): 

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

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

1447 the exchanged packets. 

1448 

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

1450 :param if2: 

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

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

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

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

1455 one. 

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

1457 

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

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

1460 See help(sniff) for more. 

1461 """ 

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

1463 if arg in kargs: 

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

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

1466 del kargs[arg] 

1467 

1468 def _init_socket(iface, # type: _GlobInterfaceType 

1469 count, # type: int 

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

1471 ): 

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

1473 if isinstance(iface, SuperSocket): 

1474 return iface, "iface%d" % count 

1475 else: 

1476 if not L2socket: 

1477 iface = resolve_iface(iface or conf.iface) 

1478 L2socket = iface.l2socket() 

1479 return L2socket(iface=iface), iface 

1480 sckt1, if1 = _init_socket(if1, 1) 

1481 sckt2, if2 = _init_socket(if2, 2) 

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

1483 xfrms = {} 

1484 if xfrm12 is not None: 

1485 xfrms[if1] = xfrm12 

1486 if xfrm21 is not None: 

1487 xfrms[if2] = xfrm21 

1488 

1489 def prn_send(pkt): 

1490 # type: (Packet) -> None 

1491 try: 

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

1493 except KeyError: 

1494 return 

1495 if pkt.sniffed_on in xfrms: 

1496 try: 

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

1498 except Exception: 

1499 log_runtime.warning( 

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

1501 'received on %s -- dropping', 

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

1503 ) 

1504 return 

1505 else: 

1506 if isinstance(_newpkt, bool): 

1507 if not _newpkt: 

1508 return 

1509 newpkt = pkt 

1510 else: 

1511 newpkt = _newpkt 

1512 else: 

1513 newpkt = pkt 

1514 try: 

1515 sendsock.send(newpkt) 

1516 except Exception: 

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

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

1519 if prn is None: 

1520 prn = prn_send 

1521 else: 

1522 prn_orig = prn 

1523 

1524 def prn(pkt): 

1525 # type: (Packet) -> Any 

1526 prn_send(pkt) 

1527 return prn_orig(pkt) 

1528 

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

1530 *args, **kargs) 

1531 

1532 

1533@conf.commands.register 

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

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

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

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

1538 

1539 if 'iface' in kargs: 

1540 iface = kargs.get('iface') 

1541 elif 'opened_socket' in kargs: 

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

1543 else: 

1544 iface = conf.iface 

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

1546 

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

1548 # for Python 2 compatibility 

1549 i = [0] 

1550 

1551 def _cb(pkt): 

1552 # type: (Packet) -> None 

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

1554 i[0] += 1 

1555 

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

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