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 

17 

18from scapy.compat import plain_str 

19from scapy.data import ETH_P_ALL 

20from scapy.config import conf 

21from scapy.error import warning 

22from scapy.interfaces import ( 

23 network_name, 

24 resolve_iface, 

25 NetworkInterface, 

26) 

27from scapy.packet import Packet 

28from scapy.pton_ntop import inet_pton 

29from scapy.utils import get_temp_file, tcpdump, wrpcap, \ 

30 ContextManagerSubprocess, PcapReader, EDecimal 

31from scapy.plist import ( 

32 PacketList, 

33 QueryAnswer, 

34 SndRcvList, 

35) 

36from scapy.error import log_runtime, log_interactive, Scapy_Exception 

37from scapy.base_classes import Gen, SetGen, ScopedIP 

38from scapy.sessions import DefaultSession 

39from scapy.supersocket import SuperSocket, IterSocket 

40 

41# Typing imports 

42from typing import ( 

43 Any, 

44 Callable, 

45 Dict, 

46 Iterator, 

47 List, 

48 Optional, 

49 Tuple, 

50 Type, 

51 Union, 

52 cast 

53) 

54from scapy.interfaces import _GlobInterfaceType 

55from scapy.plist import _PacketIterable 

56 

57if conf.route is None: 

58 # unused import, only to initialize conf.route and conf.iface* 

59 import scapy.route # noqa: F401 

60 

61################# 

62# Debug class # 

63################# 

64 

65 

66class debug: 

67 recv = PacketList([], "Received") 

68 sent = PacketList([], "Sent") 

69 match = SndRcvList([], "Matched") 

70 crashed_on = None # type: Optional[Tuple[Type[Packet], bytes]] 

71 

72 

73#################### 

74# Send / Receive # 

75#################### 

76 

77_DOC_SNDRCV_PARAMS = """ 

78 :param pks: SuperSocket instance to send/receive packets 

79 :param pkt: the packet to send 

80 :param timeout: how much time to wait after the last packet has been sent 

81 :param inter: delay between two packets during sending 

82 :param verbose: set verbosity level 

83 :param chainCC: if True, KeyboardInterrupts will be forwarded 

84 :param retry: if positive, how many times to resend unanswered packets 

85 if negative, how many times to retry when no more packets 

86 are answered 

87 :param multi: whether to accept multiple answers for the same stimulus 

88 :param first: stop after receiving the first response of any sent packet 

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 first=False, # type: bool 

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

130 prebuild=False, # type: bool 

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

132 threaded=True, # type: bool 

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

134 chainEX=False, # type: bool 

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

136 **send_kwargs, # type: Any 

137 ): 

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

139 # Instantiate all arguments 

140 if verbose is None: 

141 verbose = conf.verb 

142 if conf.debug_match: 

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

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

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

146 self.nbrecv = 0 

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

148 self.pks = pks 

149 self.rcv_pks = rcv_pks or pks 

150 self.inter = inter 

151 self.verbose = verbose 

152 self.chainCC = chainCC 

153 self.multi = multi 

154 self.timeout = timeout 

155 self.first = first 

156 self.session = session 

157 self.chainEX = chainEX 

158 self.stop_filter = stop_filter 

159 self._send_done = False 

160 self.notans = 0 

161 self.noans = 0 

162 self._flood = _flood 

163 self.threaded = threaded 

164 self.breakout = Event() 

165 self.send_kwargs = send_kwargs 

166 # Instantiate packet holders 

167 if prebuild and not self._flood: 

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

169 else: 

170 self.tobesent = pkt 

171 

172 if retry < 0: 

173 autostop = retry = -retry 

174 else: 

175 autostop = 0 

176 

177 if timeout is not None and timeout < 0: 

178 self.timeout = None 

179 

180 while retry >= 0: 

181 self.breakout.clear() 

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

183 

184 if threaded or self._flood: 

185 # Send packets in thread. 

186 snd_thread = Thread( 

187 target=self._sndrcv_snd 

188 ) 

189 snd_thread.daemon = True 

190 

191 # Start routine with callback 

192 interrupted = None 

193 try: 

194 self._sndrcv_rcv(snd_thread.start) 

195 except KeyboardInterrupt as ex: 

196 interrupted = ex 

197 

198 self.breakout.set() 

199 

200 # Ended. Let's close gracefully 

201 if self._flood: 

202 # Flood: stop send thread 

203 self._flood.stop() 

204 snd_thread.join() 

205 

206 if interrupted and self.chainCC: 

207 raise interrupted 

208 else: 

209 # Send packets, then receive. 

210 try: 

211 self._sndrcv_rcv(self._sndrcv_snd) 

212 except KeyboardInterrupt: 

213 if self.chainCC: 

214 raise 

215 

216 if multi: 

217 remain = [ 

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

219 if not hasattr(p, '_answered') 

220 ] 

221 else: 

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

223 

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

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

226 retry = autostop 

227 

228 self.tobesent = remain 

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

230 break 

231 retry -= 1 

232 

233 if conf.debug_match: 

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

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

236 

237 # Clean the ans list to delete the field _answered 

238 if multi: 

239 for snd, _ in self.ans: 

240 if hasattr(snd, '_answered'): 

241 del snd._answered 

242 

243 if verbose: 

244 print( 

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

246 "remaining %i packets" % ( 

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

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

249 ) 

250 ) 

251 

252 self.ans_result = SndRcvList(self.ans) 

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

254 

255 def results(self): 

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

257 return self.ans_result, self.unans_result 

258 

259 def _stop_sniffer_if_done(self) -> None: 

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

261 if ( 

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

263 self.first and self.noans 

264 ): 

265 if self.sniffer and self.sniffer.running: 

266 self.sniffer.stop(join=False) 

267 

268 def _sndrcv_snd(self): 

269 # type: () -> None 

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

271 i = 0 

272 p = None 

273 try: 

274 if self.verbose: 

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

276 for p in self.tobesent: 

277 # Populate the dictionary of _sndrcv_rcv 

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

279 # has not been sent 

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

281 # Send packet 

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

283 time.sleep(self.inter) 

284 if self.breakout.is_set(): 

285 break 

286 i += 1 

287 if self.verbose: 

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

289 except SystemExit: 

290 pass 

291 except Exception: 

292 if self.chainEX: 

293 raise 

294 else: 

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

296 finally: 

297 try: 

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

299 cast(Packet, p).sent_time 

300 except AttributeError: 

301 pass 

302 if self._flood: 

303 self.notans = self._flood.iterlen 

304 elif not self._send_done: 

305 self.notans = i 

306 self._send_done = True 

307 self._stop_sniffer_if_done() 

308 # In threaded mode, timeout 

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

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

311 if self.sniffer and self.sniffer.running: 

312 self.sniffer.stop() 

313 

314 def _process_packet(self, r): 

315 # type: (Packet) -> None 

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

317 if r is None: 

318 return 

319 ok = False 

320 h = r.hashret() 

321 if h in self.hsent: 

322 hlst = self.hsent[h] 

323 for i, sentpkt in enumerate(hlst): 

324 if r.answers(sentpkt): 

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

326 if self.verbose > 1: 

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

328 ok = True 

329 if not self.multi: 

330 del hlst[i] 

331 self.noans += 1 

332 else: 

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

334 self.noans += 1 

335 sentpkt._answered = 1 

336 break 

337 self._stop_sniffer_if_done() 

338 if not ok: 

339 if self.verbose > 1: 

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

341 self.nbrecv += 1 

342 if conf.debug_match: 

343 debug.recv.append(r) 

344 

345 def _sndrcv_rcv(self, callback): 

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

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

348 # This is blocking. 

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

350 self.sniffer = AsyncSniffer() 

351 self.sniffer._run( 

352 prn=self._process_packet, 

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

354 store=False, 

355 opened_socket=self.rcv_pks, 

356 session=self.session, 

357 stop_filter=self.stop_filter, 

358 started_callback=callback, 

359 chainCC=True, 

360 ) 

361 

362 

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

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

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

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

367 more appropriate in many cases. 

368 """ 

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

370 return sndrcver.results() 

371 

372 

373def __gen_send(s, # type: SuperSocket 

374 x, # type: _PacketIterable 

375 inter=0, # type: int 

376 loop=0, # type: int 

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

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

379 realtime=False, # type: bool 

380 return_packets=False, # type: bool 

381 *args, # type: Any 

382 **kargs # type: Any 

383 ): 

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

385 """ 

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

387 implement the send logic... 

388 

389 It will take care of iterating through the different packets 

390 """ 

391 if isinstance(x, str): 

392 x = conf.raw_layer(load=x) 

393 if not isinstance(x, Gen): 

394 x = SetGen(x) 

395 if verbose is None: 

396 verbose = conf.verb 

397 n = 0 

398 if count is not None: 

399 loop = -count 

400 elif not loop: 

401 loop = -1 

402 sent_packets = PacketList() if return_packets else None 

403 p = None 

404 try: 

405 while loop: 

406 dt0 = None 

407 for p in x: 

408 if realtime: 

409 ct = time.time() 

410 if dt0: 

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

412 if st > 0: 

413 time.sleep(st) 

414 else: 

415 dt0 = ct - float(p.time) 

416 s.send(p) 

417 if sent_packets is not None: 

418 sent_packets.append(p) 

419 n += 1 

420 if verbose: 

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

422 time.sleep(inter) 

423 if loop < 0: 

424 loop += 1 

425 except KeyboardInterrupt: 

426 pass 

427 finally: 

428 try: 

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

430 except AttributeError: 

431 pass 

432 if verbose: 

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

434 return sent_packets 

435 

436 

437def _send(x, # type: _PacketIterable 

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

439 inter=0, # type: int 

440 loop=0, # type: int 

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

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

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

444 realtime=False, # type: bool 

445 return_packets=False, # type: bool 

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

447 **kargs # type: Any 

448 ): 

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

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

451 need_closing = socket is None 

452 iface = resolve_iface(iface or conf.iface) 

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

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

455 count=count, verbose=verbose, 

456 realtime=realtime, return_packets=return_packets) 

457 if need_closing: 

458 socket.close() 

459 return results 

460 

461 

462@conf.commands.register 

463def send(x, # type: _PacketIterable 

464 **kargs # type: Any 

465 ): 

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

467 """ 

468 Send packets at layer 3 

469 

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

471 table: conf.route / conf.route6 

472 

473 :param x: the packets 

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

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

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

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

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

479 :param return_packets: return the sent packets 

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

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

482 :returns: None 

483 """ 

484 iface, ipv6 = _interface_selection(x, kargs.pop("iface", None)) 

485 return _send( 

486 x, 

487 lambda iface: iface.l3socket(ipv6), 

488 iface=iface, 

489 **kargs 

490 ) 

491 

492 

493@conf.commands.register 

494def sendp(x, # type: _PacketIterable 

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

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

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

498 **kargs # type: Any 

499 ): 

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

501 """ 

502 Send packets at layer 2 

503 

504 :param x: the packets 

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

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

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

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

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

510 :param return_packets: return the sent packets 

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

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

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

514 :returns: None 

515 """ 

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

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

518 return _send( 

519 x, 

520 lambda iface: iface.l2socket(), 

521 iface=iface, 

522 socket=socket, 

523 **kargs 

524 ) 

525 

526 

527@conf.commands.register 

528def sendpfast(x: _PacketIterable, 

529 pps: Optional[float] = None, 

530 mbps: Optional[float] = None, 

531 realtime: bool = False, 

532 count: Optional[int] = None, 

533 loop: int = 0, 

534 file_cache: bool = False, 

535 iface: Optional[_GlobInterfaceType] = None, 

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

537 parse_results: bool = False, 

538 ): 

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

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

541 

542 :param pps: packets per second 

543 :param mbps: MBits per second 

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

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

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

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

548 disk at each iteration 

549 :param iface: output interface 

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

551 :param parse_results: Return a dictionary of information 

552 outputted by tcpreplay (default=False) 

553 :returns: stdout, stderr, command used 

554 """ 

555 if iface is None: 

556 iface = conf.iface 

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

558 if pps is not None: 

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

560 elif mbps is not None: 

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

562 elif realtime is not None: 

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

564 else: 

565 argv.append("--topspeed") 

566 

567 if count: 

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

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

570 elif loop: 

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

572 if file_cache: 

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

574 

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

576 if replay_args is not None: 

577 argv.extend(replay_args) 

578 

579 f = get_temp_file() 

580 argv.append(f) 

581 wrpcap(f, x) 

582 results = None 

583 cmd = 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 if cmd is not None: 

598 stdout, stderr = cmd.communicate() 

599 if stderr: 

600 log_runtime.warning(stderr.decode()) 

601 if parse_results: 

602 results = _parse_tcpreplay_result(stdout, stderr, argv) 

603 elif conf.verb > 2: 

604 log_runtime.info(stdout.decode()) 

605 if os.path.exists(f): 

606 os.unlink(f) 

607 return results 

608 

609 

610def _parse_tcpreplay_result(stdout_b, stderr_b, argv): 

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

612 """ 

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

614 Tested with tcpreplay v3.4.4 

615 Tested with tcpreplay v4.1.2 

616 :param stdout: stdout of tcpreplay subprocess call 

617 :param stderr: stderr of tcpreplay subprocess call 

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

619 :return: dictionary containing the results 

620 """ 

621 try: 

622 results = {} 

623 stdout = plain_str(stdout_b).lower() 

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

625 elements = { 

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

627 "rated": (float, float, float), 

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

629 "attempted": (int,), 

630 "successful": (int,), 

631 "failed": (int,), 

632 "truncated": (int,), 

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

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

635 } 

636 multi = { 

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

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

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

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

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

642 } 

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

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

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

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

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

648 line = line.strip() 

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

650 if line.startswith(elt): 

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

652 matches = re.search(regex, line) 

653 for i, typ in enumerate(_types): 

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

655 if matches: 

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

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

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

659 return results 

660 except Exception as parse_exception: 

661 if not conf.interactive: 

662 raise 

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

664 return {} 

665 

666 

667def _interface_selection( 

668 packet: _PacketIterable, 

669 iface: Optional[str] = None, 

670) -> Tuple[NetworkInterface, bool]: 

671 """ 

672 Select the network interface according to the layer 3 destination 

673 """ 

674 if iface is not None: 

675 try: 

676 packet.dst = ScopedIP(packet.dst, scope=iface) # type: ignore 

677 except AttributeError: 

678 raise AttributeError("Cannot use iface= with this packet type.") 

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

680 ipv6 = False 

681 if src: 

682 try: 

683 inet_pton(socket.AF_INET6, src) 

684 ipv6 = True 

685 except (ValueError, OSError): 

686 pass 

687 try: 

688 iff = resolve_iface(_iff or conf.iface) 

689 except AttributeError: 

690 iff = None 

691 return iff or conf.iface, ipv6 

692 

693 

694@conf.commands.register 

695def sr(x, # type: _PacketIterable 

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

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

698 nofilter=0, # type: int 

699 *args, # type: Any 

700 **kargs # type: Any 

701 ): 

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

703 """ 

704 Send and receive packets at layer 3 

705 

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

707 table: conf.route / conf.route6 

708 """ 

709 iface, ipv6 = _interface_selection(x, kargs.pop("iface", None)) 

710 s = iface.l3socket(ipv6)( 

711 promisc=promisc, filter=filter, 

712 iface=iface, nofilter=nofilter, 

713 ) 

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

715 s.close() 

716 return result 

717 

718 

719@conf.commands.register 

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

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

722 """ 

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

724 

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

726 table: conf.route / conf.route6 

727 """ 

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

729 if ans: 

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

731 return None 

732 

733 

734@conf.commands.register 

735def srp(x, # type: _PacketIterable 

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

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

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

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

740 nofilter=0, # type: int 

741 type=ETH_P_ALL, # type: int 

742 *args, # type: Any 

743 **kargs # type: Any 

744 ): 

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

746 """ 

747 Send and receive packets at layer 2 

748 """ 

749 if iface is None and iface_hint is not None: 

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

751 iface = resolve_iface(iface or conf.iface) 

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

753 filter=filter, nofilter=nofilter, type=type) 

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

755 s.close() 

756 return result 

757 

758 

759@conf.commands.register 

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

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

762 """ 

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

764 """ 

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

766 if len(ans) > 0: 

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

768 return None 

769 

770 

771# Append doc 

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

773 if sr_func.__doc__ is not None: 

774 sr_func.__doc__ += _DOC_SNDRCV_PARAMS 

775 

776 

777# SEND/RECV LOOP METHODS 

778 

779 

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

781 pkts, # type: _PacketIterable 

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

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

784 inter=1, # type: int 

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

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

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

788 store=1, # type: int 

789 *args, # type: Any 

790 **kargs # type: Any 

791 ): 

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

793 n = 0 

794 r = 0 

795 ct = conf.color_theme 

796 if verbose is None: 

797 verbose = conf.verb 

798 parity = 0 

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

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

801 if timeout is None: 

802 timeout = min(2 * inter, 5) 

803 try: 

804 while True: 

805 parity ^= 1 

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

807 if count is not None: 

808 if count == 0: 

809 break 

810 count -= 1 

811 start = time.monotonic() 

812 if verbose > 1: 

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

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

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

816 r += len(res[0]) 

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

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

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

820 for rcv in res[0]: 

821 print(col(prn(rcv))) 

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

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

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

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

826 for fail in res[1]: 

827 print(col(prnfail(fail))) 

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

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

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

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

832 )) 

833 if verbose == 1: 

834 if res[0]: 

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

836 if res[1]: 

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

838 if store: 

839 ans += res[0] 

840 unans += res[1] 

841 end = time.monotonic() 

842 if end - start < inter: 

843 time.sleep(inter + start - end) 

844 except KeyboardInterrupt: 

845 pass 

846 

847 if verbose and n > 0: 

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

849 return SndRcvList(ans), PacketList(unans) 

850 

851 

852@conf.commands.register 

853def srloop(pkts, # type: _PacketIterable 

854 *args, # type: Any 

855 **kargs # type: Any 

856 ): 

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

858 """ 

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

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

861 """ 

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

863 

864 

865@conf.commands.register 

866def srploop(pkts, # type: _PacketIterable 

867 *args, # type: Any 

868 **kargs # type: Any 

869 ): 

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

871 """ 

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

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

874 """ 

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

876 

877# SEND/RECV FLOOD METHODS 

878 

879 

880class _FloodGenerator(object): 

881 def __init__(self, tobesent, maxretries): 

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

883 self.tobesent = tobesent 

884 self.maxretries = maxretries 

885 self.stopevent = Event() 

886 self.iterlen = 0 

887 

888 def __iter__(self): 

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

890 i = 0 

891 while True: 

892 i += 1 

893 j = 0 

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

895 return 

896 for p in self.tobesent: 

897 if self.stopevent.is_set(): 

898 return 

899 j += 1 

900 yield p 

901 if self.iterlen == 0: 

902 self.iterlen = j 

903 

904 @property 

905 def sent_time(self): 

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

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

908 

909 @sent_time.setter 

910 def sent_time(self, val): 

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

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

913 

914 def stop(self): 

915 # type: () -> None 

916 self.stopevent.set() 

917 

918 

919def sndrcvflood(pks, # type: SuperSocket 

920 pkt, # type: _PacketIterable 

921 inter=0, # type: int 

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

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

924 chainCC=False, # type: bool 

925 timeout=None # type: Optional[int] 

926 ): 

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

928 """sndrcv equivalent for flooding.""" 

929 

930 flood_gen = _FloodGenerator(pkt, maxretries) 

931 return sndrcv( 

932 pks, flood_gen, 

933 inter=inter, verbose=verbose, 

934 chainCC=chainCC, timeout=timeout, 

935 _flood=flood_gen 

936 ) 

937 

938 

939@conf.commands.register 

940def srflood(x, # type: _PacketIterable 

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

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

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

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

945 *args, # type: Any 

946 **kargs # type: Any 

947 ): 

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

949 """Flood and receive packets at layer 3 

950 

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

952 table: conf.route / conf.route6 

953 

954 :param prn: function applied to packets received 

955 :param unique: only consider packets whose print 

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

957 :param filter: provide a BPF filter 

958 """ 

959 iface, ipv6 = _interface_selection(x, kargs.pop("iface", None)) 

960 s = iface.l3socket(ipv6)( 

961 promisc=promisc, filter=filter, 

962 iface=iface, nofilter=nofilter, 

963 ) 

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

965 s.close() 

966 return r 

967 

968 

969@conf.commands.register 

970def sr1flood(x, # type: _PacketIterable 

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

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

973 nofilter=0, # type: int 

974 *args, # type: Any 

975 **kargs # type: Any 

976 ): 

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

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

979 

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

981 table: conf.route / conf.route6 

982 

983 :param prn: function applied to packets received 

984 :param verbose: set verbosity level 

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

986 :param filter: provide a BPF filter 

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

988 """ 

989 iface, ipv6 = _interface_selection(x, kargs.pop("iface", None)) 

990 s = iface.l3socket(ipv6)( 

991 promisc=promisc, filter=filter, 

992 nofilter=nofilter, iface=iface, 

993 ) 

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

995 s.close() 

996 if len(ans) > 0: 

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

998 return None 

999 

1000 

1001@conf.commands.register 

1002def srpflood(x, # type: _PacketIterable 

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

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

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

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

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

1008 *args, # type: Any 

1009 **kargs # type: Any 

1010 ): 

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

1012 """Flood and receive packets at layer 2 

1013 

1014 :param prn: function applied to packets received 

1015 :param unique: only consider packets whose print 

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

1017 :param filter: provide a BPF filter 

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

1019 """ 

1020 if iface is None and iface_hint is not None: 

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

1022 iface = resolve_iface(iface or conf.iface) 

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

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

1025 s.close() 

1026 return r 

1027 

1028 

1029@conf.commands.register 

1030def srp1flood(x, # type: _PacketIterable 

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

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

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

1034 nofilter=0, # type: int 

1035 *args, # type: Any 

1036 **kargs # type: Any 

1037 ): 

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

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

1040 

1041 :param prn: function applied to packets received 

1042 :param verbose: set verbosity level 

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

1044 :param filter: provide a BPF filter 

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

1046 """ 

1047 iface = resolve_iface(iface or conf.iface) 

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

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

1050 s.close() 

1051 if len(ans) > 0: 

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

1053 return None 

1054 

1055# SNIFF METHODS 

1056 

1057 

1058def _offline_pcap_reader(source, flt, quiet): 

1059 # type: (Any, Optional[str], bool) -> PcapReader 

1060 """Build a PcapReader for one sniff() offline source. 

1061 

1062 The source is whatever tcpdump() accepts: a filename, an IterSocket over 

1063 packets, or an open file descriptor. Without a filter it is read directly. 

1064 With a filter the packets are prefiltered through a tcpdump subprocess; 

1065 that process is attached to the reader so its close() reaps it. Reading it 

1066 through a bare file descriptor used to leak the process as a zombie 

1067 (#4512). 

1068 """ 

1069 if flt is None: 

1070 return PcapReader(source) 

1071 proc = tcpdump(source, args=["-w", "-"], flt=flt, getproc=True, quiet=quiet) 

1072 reader = PcapReader(proc.stdout) 

1073 reader.subproc = proc 

1074 return reader 

1075 

1076 

1077class AsyncSniffer(object): 

1078 """ 

1079 Sniff packets and return a list of packets. 

1080 

1081 Args: 

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

1083 store: whether to store sniffed packets or discard them 

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

1085 is displayed. 

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

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

1088 --Ex: session=TCPSession 

1089 See below for more details. 

1090 filter: BPF filter to apply. 

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

1092 further action may be done. 

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

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

1095 instead of sniffing them 

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

1097 (default: False). 

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

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

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

1101 .recv() on. 

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

1103 we have to stop the capture after this packet. 

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

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

1106 on the default interface). 

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

1108 started_callback: called as soon as the sniffer starts sniffing 

1109 (default: None). 

1110 

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

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

1113 label (see examples below). 

1114 

1115 For more information about the session argument, see 

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

1117 

1118 Examples: synchronous 

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

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

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

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

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

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

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

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

1127 ... pkt.summary())) 

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

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

1130 ... pkt.summary())) 

1131 

1132 Examples: asynchronous 

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

1134 >>> t.start() 

1135 >>> time.sleep(1) 

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

1137 >>> t.stop() 

1138 """ 

1139 

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

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

1142 # Store keyword arguments 

1143 self.args = args 

1144 if "timeout" in kwargs: 

1145 raise ValueError( 

1146 "'timeout' isn't supported with AsyncSniffer. Use join(timeout=1)" 

1147 ) 

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( 

1223 (_offline_pcap_reader(fname, flt, quiet), fname) # type: ignore 

1224 for fname in offline 

1225 ) 

1226 elif isinstance(offline, dict): 

1227 # Dict of files 

1228 sniff_sockets.update( 

1229 (_offline_pcap_reader(fname, flt, quiet), label) # type: ignore 

1230 for fname, label in offline.items() 

1231 ) 

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

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

1234 offline = IterSocket(offline) 

1235 sniff_sockets[ 

1236 offline if flt is None 

1237 else _offline_pcap_reader(offline, flt, quiet) 

1238 ] = offline 

1239 else: 

1240 # Other (file descriptors...) 

1241 sniff_sockets[ 

1242 _offline_pcap_reader(offline, flt, quiet) # type: ignore 

1243 ] = offline 

1244 if not sniff_sockets or iface is not None: 

1245 # The _RL2 function resolves the L2socket of an iface 

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

1247 if isinstance(iface, list): 

1248 sniff_sockets.update( 

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

1250 ifname) 

1251 for ifname in iface 

1252 ) 

1253 elif isinstance(iface, dict): 

1254 sniff_sockets.update( 

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

1256 iflabel) 

1257 for ifname, iflabel in iface.items() 

1258 ) 

1259 else: 

1260 iface = iface or conf.iface 

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

1262 **karg)] = iface 

1263 

1264 # Get select information from the sockets 

1265 _main_socket = next(iter(sniff_sockets)) 

1266 select_func = _main_socket.select 

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

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

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

1270 warning("Warning: inconsistent socket types ! " 

1271 "The used select function " 

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

1273 

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

1275 if not nonblocking_socket: 

1276 # select is blocking: Add special control socket 

1277 from scapy.automaton import ObjectPipe 

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

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

1280 

1281 def stop_cb(): 

1282 # type: () -> None 

1283 if self.running and close_pipe: 

1284 close_pipe.send(None) 

1285 self.continue_sniff = False 

1286 self.stop_cb = stop_cb 

1287 else: 

1288 # select is non blocking 

1289 def stop_cb(): 

1290 # type: () -> None 

1291 self.continue_sniff = False 

1292 self.stop_cb = stop_cb 

1293 

1294 try: 

1295 self.continue_sniff = True 

1296 if started_callback: 

1297 started_callback() 

1298 

1299 # Start timeout 

1300 if timeout is not None: 

1301 stoptime = time.monotonic() + timeout 

1302 remain = None 

1303 

1304 while sniff_sockets and self.continue_sniff: 

1305 if timeout is not None: 

1306 remain = stoptime - time.monotonic() 

1307 if remain <= 0: 

1308 break 

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

1310 dead_sockets = [] 

1311 for s in sockets: 

1312 if s is close_pipe: # type: ignore 

1313 break 

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

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

1316 try: 

1317 packets = session.recv(s) 

1318 # A session can return multiple objects 

1319 for p in packets: 

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

1321 if lfilter and not lfilter(p): 

1322 continue 

1323 # post-processing 

1324 self.count += 1 

1325 if store: 

1326 lst.append(p) 

1327 if prn: 

1328 result = prn(p) 

1329 if result is not None: 

1330 print(result) 

1331 # check 

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

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

1334 self.continue_sniff = False 

1335 break 

1336 except EOFError: 

1337 # End of stream 

1338 try: 

1339 s.close() 

1340 except Exception: 

1341 pass 

1342 dead_sockets.append(s) 

1343 continue 

1344 except Exception as ex: 

1345 msg = " It was closed." 

1346 try: 

1347 # Make sure it's closed 

1348 s.close() 

1349 except Exception as ex2: 

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

1351 warning( 

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

1353 ) 

1354 dead_sockets.append(s) 

1355 if conf.debug_dissector >= 2: 

1356 raise 

1357 continue 

1358 # Removed dead sockets 

1359 for s in dead_sockets: 

1360 del sniff_sockets[s] 

1361 if len(sniff_sockets) == 1 and \ 

1362 close_pipe in sniff_sockets: # type: ignore 

1363 # Only the close_pipe left 

1364 del sniff_sockets[close_pipe] # type: ignore 

1365 except KeyboardInterrupt: 

1366 if chainCC: 

1367 raise 

1368 self.running = False 

1369 if opened_socket is None: 

1370 for s in sniff_sockets: 

1371 s.close() 

1372 elif close_pipe: 

1373 close_pipe.close() 

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

1375 

1376 def start(self): 

1377 # type: () -> None 

1378 """Starts AsyncSniffer in async mode""" 

1379 self._setup_thread() 

1380 if self.thread: 

1381 self.thread.start() 

1382 

1383 def stop(self, join=True): 

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

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

1386 if self.running: 

1387 self.stop_cb() 

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

1389 # Never started -> is there an exception? 

1390 if self.exception is not None: 

1391 raise self.exception 

1392 return None 

1393 if self.continue_sniff: 

1394 raise Scapy_Exception( 

1395 "Unsupported (offline or unsupported socket)" 

1396 ) 

1397 if join: 

1398 self.join() 

1399 return self.results 

1400 return None 

1401 else: 

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

1403 

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

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

1406 if self.thread: 

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

1408 if self.exception is not None: 

1409 raise self.exception 

1410 

1411 

1412@conf.commands.register 

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

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

1415 sniffer = AsyncSniffer() 

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

1417 return cast(PacketList, sniffer.results) 

1418 

1419 

1420sniff.__doc__ = AsyncSniffer.__doc__ 

1421 

1422 

1423@conf.commands.register 

1424def bridge_and_sniff(if1, # type: _GlobInterfaceType 

1425 if2, # type: _GlobInterfaceType 

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

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

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

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

1430 *args, # type: Any 

1431 **kargs # type: Any 

1432 ): 

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

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

1435 the exchanged packets. 

1436 

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

1438 :param if2: 

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

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

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

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

1443 one. 

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

1445 

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

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

1448 See help(sniff) for more. 

1449 """ 

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

1451 if arg in kargs: 

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

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

1454 del kargs[arg] 

1455 

1456 def _init_socket(iface, # type: _GlobInterfaceType 

1457 count, # type: int 

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

1459 ): 

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

1461 if isinstance(iface, SuperSocket): 

1462 return iface, "iface%d" % count 

1463 else: 

1464 if not L2socket: 

1465 iface = resolve_iface(iface or conf.iface) 

1466 L2socket = iface.l2socket() 

1467 return L2socket(iface=iface), iface 

1468 sckt1, if1 = _init_socket(if1, 1) 

1469 sckt2, if2 = _init_socket(if2, 2) 

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

1471 xfrms = {} 

1472 if xfrm12 is not None: 

1473 xfrms[if1] = xfrm12 

1474 if xfrm21 is not None: 

1475 xfrms[if2] = xfrm21 

1476 

1477 def prn_send(pkt): 

1478 # type: (Packet) -> None 

1479 try: 

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

1481 except KeyError: 

1482 return 

1483 if pkt.sniffed_on in xfrms: 

1484 try: 

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

1486 except Exception: 

1487 log_runtime.warning( 

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

1489 'received on %s -- dropping', 

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

1491 ) 

1492 return 

1493 else: 

1494 if isinstance(_newpkt, bool): 

1495 if not _newpkt: 

1496 return 

1497 newpkt = pkt 

1498 else: 

1499 newpkt = _newpkt 

1500 else: 

1501 newpkt = pkt 

1502 try: 

1503 sendsock.send(newpkt) 

1504 except Exception: 

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

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

1507 if prn is None: 

1508 prn = prn_send 

1509 else: 

1510 prn_orig = prn 

1511 

1512 def prn(pkt): 

1513 # type: (Packet) -> Any 

1514 prn_send(pkt) 

1515 return prn_orig(pkt) 

1516 

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

1518 *args, **kargs) 

1519 

1520 

1521@conf.commands.register 

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

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

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

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

1526 

1527 if 'iface' in kargs: 

1528 iface = kargs.get('iface') 

1529 elif 'opened_socket' in kargs: 

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

1531 else: 

1532 iface = conf.iface 

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

1534 

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

1536 # for Python 2 compatibility 

1537 i = [0] 

1538 

1539 def _cb(pkt): 

1540 # type: (Packet) -> None 

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

1542 i[0] += 1 

1543 

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

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