diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py index 051247a7979..50205b2e2ce 100644 --- a/scapy/sendrecv.py +++ b/scapy/sendrecv.py @@ -74,28 +74,50 @@ class debug: # Send / Receive # #################### -_DOC_SNDRCV_PARAMS = """ - :param pks: SuperSocket instance to send/receive packets - :param pkt: the packet to send - :param timeout: how much time to wait after the last packet has been sent - :param inter: delay between two packets during sending - :param verbose: set verbosity level - :param chainCC: if True, KeyboardInterrupts will be forwarded - :param retry: if positive, how many times to resend unanswered packets - if negative, how many times to retry when no more packets - are answered - :param multi: whether to accept multiple answers for the same stimulus - :param rcv_pks: if set, will be used instead of pks to receive packets. - packets will still be sent through pks - :param prebuild: pre-build the packets before starting to send them. - Automatically enabled when a generator is passed as the packet - :param _flood: - :param threaded: if True, packets will be sent in an individual thread - :param session: a flow decoder used to handle stream of packets - :param chainEX: if True, exceptions during send will be forwarded +_DOC_SNDRCV_PARAMS_BODY = """ + :param pkt: Packet or iterable of packets to be sent. + :param timeout: How much time to wait after the last packet + has been sent. Defaults to None. + :param inter: Delay between two packets during sending. Defaults to 0. + :param verbose: Set verbosity level. Defaults to None. + :param chainCC: If True, KeyboardInterrupts will be forwarded. + Defaults to False. + :param retry: If positive, how many times to resend unanswered packets. + If negative, how many times to retry when no more packets + are answered. Defaults to 0. + :param multi: Whether to accept multiple answers for the same stimulus. + Defaults to False. + :param rcv_pks: If set, will be used instead of pks to receive packets. + Packets will still be sent through pks. + Defaults to None. + :param prebuild: Pre-build the packets before starting to send them. + Automatically enabled when a generator is passed as the + packet. Defaults to False. + :param _flood: _FloodGenerator object, internally used by `flood()` + methods. Defaults to None. + :param threaded: If True, packets will be sent in an individual thread. + Defaults to False. + :param session: A flow decoder used to handle the stream of packets. + Defaults to None. + :param chainEX: If True, exceptions during send will be forwarded. + Defaults to False. +""" + +_DOC_SNDRCV_PARAMS_TAIL = """ + :return: A tuple, consisting of two packet lists, one with + answered packets, the other with unanswered packets + """ + +_DOC_SNDRCV1_PARAMS_TAIL = """ + :return: A received Packet answering the sent packet, or None """ +# Append doc in SuperSocket +SuperSocket.sr.__doc__ += _DOC_SNDRCV_PARAMS_BODY + _DOC_SNDRCV_PARAMS_TAIL # type: ignore # noqa: E501 +SuperSocket.sr1.__doc__ += _DOC_SNDRCV_PARAMS_BODY + _DOC_SNDRCV1_PARAMS_TAIL # type: ignore # noqa: E501 + + _GlobSessionType = Union[Type[DefaultSession], DefaultSession] @@ -112,6 +134,34 @@ class SndRcvHandler(object): when sending a big amount of packets. Disabled by default - DEVS: store the outgoing timestamp right BEFORE sending the packet to avoid races that could result in negative latency. We aren't Stadia + + :param pks: SuperSocket instance to send/receive packets + :param pkt: Packet or iterable of packets to be sent. + :param timeout: How much time to wait after the last packet + has been sent. Defaults to None. + :param inter: Delay between two packets during sending. Defaults to 0. + :param verbose: Set verbosity level. Defaults to None. + :param chainCC: If True, KeyboardInterrupts will be forwarded. + Defaults to False. + :param retry: If positive, how many times to resend unanswered packets. + If negative, how many times to retry when no more packets + are answered. Defaults to 0. + :param multi: Whether to accept multiple answers for the same stimulus. + Defaults to False. + :param rcv_pks: If set, will be used instead of pks to receive packets. + Packets will still be sent through pks. + Defaults to None. + :param prebuild: Pre-build the packets before starting to send them. + Automatically enabled when a generator is passed as the + packet. Defaults to False. + :param _flood: _FloodGenerator object, internally used by `flood()` + methods. Defaults to None. + :param threaded: If True, packets will be sent in an individual thread. + Defaults to False. + :param session: A flow decoder used to handle the stream of packets. + Defaults to None. + :param chainEX: If True, exceptions during send will be forwarded. + Defaults to False. """ def __init__(self, pks, # type: SuperSocket @@ -646,7 +696,7 @@ def _interface_selection(iface, # type: Optional[_GlobInterfaceType] @conf.commands.register -def sr(x, # type: _PacketIterable +def sr(pkt, # type: _PacketIterable promisc=None, # type: Optional[bool] filter=None, # type: Optional[str] iface=None, # type: Optional[_GlobInterfaceType] @@ -657,13 +707,46 @@ def sr(x, # type: _PacketIterable # type: (...) -> Tuple[SndRcvList, PacketList] """ Send and receive packets at layer 3 + + :param pkt: Packet or iterable of packets to be sent. + :param promisc: Sets the socket in promisc mode, if True. + :param iface: Use a specific network interface, if provided. + :param filter: Filter string applied to the underlying socket. + :param nofilter: + :param timeout: How much time to wait after the last packet + has been sent. Defaults to None. + :param inter: Delay between two packets during sending. Defaults to 0. + :param verbose: Set verbosity level. Defaults to None. + :param chainCC: If True, KeyboardInterrupts will be forwarded. + Defaults to False. + :param retry: If positive, how many times to resend unanswered packets. + If negative, how many times to retry when no more packets + are answered. Defaults to 0. + :param multi: Whether to accept multiple answers for the same stimulus. + Defaults to False. + :param rcv_pks: If set, will be used instead of pks to receive packets. + Packets will still be sent through pks. + Defaults to None. + :param prebuild: Pre-build the packets before starting to send them. + Automatically enabled when a generator is passed as the + packet. Defaults to False. + :param _flood: _FloodGenerator object, internally used by `flood()` + methods. Defaults to None. + :param threaded: If True, packets will be sent in an individual thread. + Defaults to False. + :param session: A flow decoder used to handle the stream of packets. + Defaults to None. + :param chainEX: If True, exceptions during send will be forwarded. + Defaults to False. + :return: A tuple, consisting of two packet lists, one with + answered packets, the other with unanswered packets """ - iface, ipv6 = _interface_selection(iface, x) + iface, ipv6 = _interface_selection(iface, pkt) s = iface.l3socket(ipv6)( promisc=promisc, filter=filter, iface=iface, nofilter=nofilter, ) - result = sndrcv(s, x, *args, **kargs) + result = sndrcv(s, pkt, *args, **kargs) s.close() return result @@ -673,6 +756,38 @@ def sr1(*args, **kargs): # type: (*Any, **Any) -> Optional[Packet] """ Send packets at layer 3 and return only the first answer + + :param pkt: Packet or iterable of packets to be sent. + :param promisc: Sets the socket in promisc mode, if True. + :param iface: Use a specific network interface, if provided. + :param filter: Filter string applied to the underlying socket. + :param nofilter: + :param timeout: How much time to wait after the last packet + has been sent. Defaults to None. + :param inter: Delay between two packets during sending. Defaults to 0. + :param verbose: Set verbosity level. Defaults to None. + :param chainCC: If True, KeyboardInterrupts will be forwarded. + Defaults to False. + :param retry: If positive, how many times to resend unanswered packets. + If negative, how many times to retry when no more packets + are answered. Defaults to 0. + :param multi: Whether to accept multiple answers for the same stimulus. + Defaults to False. + :param rcv_pks: If set, will be used instead of pks to receive packets. + Packets will still be sent through pks. + Defaults to None. + :param prebuild: Pre-build the packets before starting to send them. + Automatically enabled when a generator is passed as the + packet. Defaults to False. + :param _flood: _FloodGenerator object, internally used by `flood()` + methods. Defaults to None. + :param threaded: If True, packets will be sent in an individual thread. + Defaults to False. + :param session: A flow decoder used to handle the stream of packets. + Defaults to None. + :param chainEX: If True, exceptions during send will be forwarded. + Defaults to False. + :return: A received Packet answering the sent packet, or None """ ans, _ = sr(*args, **kargs) if ans: @@ -681,7 +796,7 @@ def sr1(*args, **kargs): @conf.commands.register -def srp(x, # type: _PacketIterable +def srp(pkt, # type: _PacketIterable promisc=None, # type: Optional[bool] iface=None, # type: Optional[_GlobInterfaceType] iface_hint=None, # type: Optional[str] @@ -694,13 +809,50 @@ def srp(x, # type: _PacketIterable # type: (...) -> Tuple[SndRcvList, PacketList] """ Send and receive packets at layer 2 + + :param pkt: Packet or iterable of packets to be sent. + :param promisc: Sets the socket in promisc mode, if True. + :param iface: Use a specific network interface, if provided. + :param iface_hint: The interface used to connect to the host based on + the route information, if provided. + :param filter: Filter string applied to the underlying socket. + :param nofilter: + :param type: Type of the underlying socket + :param timeout: How much time to wait after the last packet + has been sent. Defaults to None. + :param inter: Delay between two packets during sending. Defaults to 0. + :param verbose: Set verbosity level. Defaults to None. + :param chainCC: If True, KeyboardInterrupts will be forwarded. + Defaults to False. + :param retry: If positive, how many times to resend unanswered packets. + If negative, how many times to retry when no more packets + are answered. Defaults to 0. + :param multi: Whether to accept multiple answers for the same stimulus. + Defaults to False. + :param rcv_pks: If set, will be used instead of pks to receive packets. + Packets will still be sent through pks. + Defaults to None. + :param prebuild: Pre-build the packets before starting to send them. + Automatically enabled when a generator is passed as the + packet. Defaults to False. + :param _flood: _FloodGenerator object, internally used by `flood()` + methods. Defaults to None. + :param threaded: If True, packets will be sent in an individual thread. + Defaults to False. + :param session: A flow decoder used to handle the stream of packets. + Defaults to None. + :param chainEX: If True, exceptions during send will be forwarded. + Defaults to False. + + :return: A tuple, consisting of two packet lists, one with + answered packets, the other with unanswered packets """ if iface is None and iface_hint is not None: iface = conf.route.route(iface_hint)[0] iface = resolve_iface(iface or conf.iface) s = iface.l2socket()(promisc=promisc, iface=iface, filter=filter, nofilter=nofilter, type=type) - result = sndrcv(s, x, *args, **kargs) + result = sndrcv(s, pkt, *args, **kargs) s.close() return result @@ -710,6 +862,41 @@ def srp1(*args, **kargs): # type: (*Any, **Any) -> Optional[Packet] """ Send and receive packets at layer 2 and return only the first answer + + :param pkt: Packet or iterable of packets to be sent. + :param promisc: Sets the socket in promisc mode, if True. + :param iface: Use a specific network interface, if provided. + :param iface_hint: The interface used to connect to the host based on + the route information, if provided. + :param filter: Filter string applied to the underlying socket. + :param nofilter: + :param type: Type of the underlying socket + :param timeout: How much time to wait after the last packet + has been sent. Defaults to None. + :param inter: Delay between two packets during sending. Defaults to 0. + :param verbose: Set verbosity level. Defaults to None. + :param chainCC: If True, KeyboardInterrupts will be forwarded. + Defaults to False. + :param retry: If positive, how many times to resend unanswered packets. + If negative, how many times to retry when no more packets + are answered. Defaults to 0. + :param multi: Whether to accept multiple answers for the same stimulus. + Defaults to False. + :param rcv_pks: If set, will be used instead of pks to receive packets. + Packets will still be sent through pks. + Defaults to None. + :param prebuild: Pre-build the packets before starting to send them. + Automatically enabled when a generator is passed as the + packet. Defaults to False. + :param _flood: _FloodGenerator object, internally used by `flood()` + methods. Defaults to None. + :param threaded: If True, packets will be sent in an individual thread. + Defaults to False. + :param session: A flow decoder used to handle the stream of packets. + Defaults to None. + :param chainEX: If True, exceptions during send will be forwarded. + Defaults to False. + :return: A received Packet answering the sent packet, or None """ ans, _ = srp(*args, **kargs) if len(ans) > 0: @@ -717,15 +904,8 @@ def srp1(*args, **kargs): return None -# Append doc -for sr_func in [srp, srp1, sr, sr1]: - if sr_func.__doc__ is not None: - sr_func.__doc__ += _DOC_SNDRCV_PARAMS - - # SEND/RECV LOOP METHODS - def __sr_loop(srfunc, # type: Callable[..., Tuple[SndRcvList, PacketList]] pkts, # type: _PacketIterable prn=lambda x: x[1].summary(), # type: Optional[Callable[[QueryAnswer], Any]] # noqa: E501 @@ -1000,40 +1180,49 @@ def srp1flood(x, # type: _PacketIterable # SNIFF METHODS -class AsyncSniffer(object): - """ - Sniff packets and return a list of packets. - - Args: - count: number of packets to capture. 0 means infinity. - store: whether to store sniffed packets or discard them - prn: function to apply to each packet. If something is returned, it - is displayed. - --Ex: prn = lambda x: x.summary() - session: a session = a flow decoder used to handle stream of packets. - --Ex: session=TCPSession - See below for more details. - filter: BPF filter to apply. - lfilter: Python function applied to each packet to determine if - further action may be done. - --Ex: lfilter = lambda x: x.haslayer(Padding) - offline: PCAP file (or list of PCAP files) to read packets from, - instead of sniffing them - quiet: when set to True, the process stderr is discarded - (default: False). - timeout: stop sniffing after a given time (default: None). - L2socket: use the provided L2socket (default: use conf.L2listen). - opened_socket: provide an object (or a list of objects) ready to use - .recv() on. - stop_filter: Python function applied to each packet to determine if - we have to stop the capture after this packet. - --Ex: stop_filter = lambda x: x.haslayer(TCP) - iface: interface or list of interfaces (default: None for sniffing - on the default interface). - monitor: use monitor mode. May not be available on all OS - started_callback: called as soon as the sniffer starts sniffing - (default: None). +_DOC_SNIFF_PARAMS = """ + :param count: Number of packets to capture. 0 means infinity. + :type count: int + :param store: Whether to store sniffed packets or discard them. + :type store: bool + :param offline: PCAP file (or list of PCAP files) to read packets from, + instead of sniffing them. + :type offline: Any + :param quiet: When set to True, the process stderr is discarded. + (default: False). + :type quiet: bool + :param prn: Function to apply to each packet. If something is returned, + it is displayed. + --Ex: prn = lambda x: x.summary() + :type prn: Optional[Callable[[Packet], Any]] + :param lfilter: Python function applied to each packet to determine if + further action may be done. + :type lfilter: Optional[Callable[[Packet], bool]] + :param L2socket: Use the provided L2socket (default: use conf.L2listen). + :type L2socket: Optional[Type[SuperSocket]] + :param timeout: Stop sniffing after a given time (default: None). + :type timeout: Optional[int] + :param opened_socket: Provide an object (or a list of objects) ready to + use .recv() on. + :type opened_socket: Optional[SuperSocket] + :param stop_filter: Python function applied to each packet to determine if + we have to stop the capture after this packet. + :type stop_filter: Optional[Callable[[Packet], bool]] + :param iface: Interface or list of interfaces (default: None for sniffing + on all interfaces). + :type iface: Optional[_GlobInterfaceType] + :param started_callback: Called as soon as the sniffer starts sniffing + (default: None). + :type started_callback: Optional[Callable[[], Any]] + :param session: A session, which is a flow decoder used to handle a stream + of packets. See the documentation for more details. + :type session: Optional[_GlobSessionType] + :param session_kwargs: Additional keyword arguments for session initialization. + :type session_kwargs: Dict[str, Any] + +""" +_DOC_ASYNC_SNIFF = """ The iface, offline and opened_socket parameters can be either an element, a list of elements, or a dict object mapping an element to a label (see examples below). @@ -1063,6 +1252,11 @@ class AsyncSniffer(object): >>> t.stop() """ + +class AsyncSniffer(object): + """Sniff packets and return a list of packets. + """ + def __init__(self, *args, **kwargs): # type: (*Any, **Any) -> None # Store keyword arguments @@ -1333,6 +1527,9 @@ def join(self, *args, **kwargs): self.thread.join(*args, **kwargs) +AsyncSniffer.__doc__ = AsyncSniffer.__doc__ + _DOC_SNIFF_PARAMS + _DOC_ASYNC_SNIFF # type: ignore # noqa: E501 + + @conf.commands.register def sniff(*args, **kwargs): # type: (*Any, **Any) -> PacketList @@ -1341,7 +1538,7 @@ def sniff(*args, **kwargs): return cast(PacketList, sniffer.results) -sniff.__doc__ = AsyncSniffer.__doc__ +SuperSocket.sniff.__doc__ = sniff.__doc__ = AsyncSniffer.__doc__ @conf.commands.register @@ -1358,18 +1555,21 @@ def bridge_and_sniff(if1, # type: _GlobInterfaceType """Forward traffic between interfaces if1 and if2, sniff and return the exchanged packets. - :param if1: the interfaces to use (interface names or opened sockets). - :param if2: - :param xfrm12: a function to call when forwarding a packet from if1 to + :param if1: The interfaces to use (interface names or opened sockets). + :type if1: _GlobInterfaceType + + :param if2: The interfaces to use (interface names or opened sockets). + :type if2: _GlobInterfaceType + + :param xfrm12: A function to call when forwarding a packet from if1 to if2. If it returns True, the packet is forwarded as it. If it returns False or None, the packet is discarded. If it returns a - packet, this packet is forwarded instead of the original packet - one. - :param xfrm21: same as xfrm12 for packets forwarded from if2 to if1. + packet, this packet is forwarded instead of the original packet. + :type xfrm12: Optional[Callable[[Packet], Union[Packet, bool]]] + + :param xfrm21: Same as xfrm12 for packets forwarded from if2 to if1. + :type xfrm21: Optional[Callable[[Packet], Union[Packet, bool]]] - The other arguments are the same than for the function sniff(), - except for offline, opened_socket and iface that are ignored. - See help(sniff) for more. """ for arg in ['opened_socket', 'offline', 'iface']: if arg in kargs: @@ -1442,11 +1642,15 @@ def prn(pkt): *args, **kargs) +bridge_and_sniff.__doc__ = bridge_and_sniff.__doc__ + _DOC_SNIFF_PARAMS # type: ignore # noqa: E501 + + @conf.commands.register def tshark(*args, **kargs): # type: (Any, Any) -> None """Sniff packets and print them calling pkt.summary(). - This tries to replicate what text-wireshark (tshark) would look like""" + This tries to replicate what text-wireshark (tshark) would look like. + """ if 'iface' in kargs: iface = kargs.get('iface') @@ -1467,3 +1671,7 @@ def _cb(pkt): sniff(prn=_cb, store=False, *args, **kargs) print("\n%d packet%s captured" % (i[0], 's' if i[0] > 1 else '')) + + +tshark.__doc__ = tshark.__doc__ + _DOC_SNIFF_PARAMS # type: ignore # noqa: E501 +SuperSocket.tshark.__doc__ = tshark.__doc__ diff --git a/scapy/supersocket.py b/scapy/supersocket.py index a62742e2c2b..7a14b75ddf7 100644 --- a/scapy/supersocket.py +++ b/scapy/supersocket.py @@ -103,6 +103,13 @@ def __init__(self, def send(self, x): # type: (Packet) -> int + """Sends a `Packet` object + + :param x: `Packet` to be send + :type x: Packet + :return: Number of bytes that have been sent + :rtype: int + """ sx = raw(x) try: x.sent_time = time.time() @@ -117,7 +124,15 @@ def send(self, x): if WINDOWS: def _recv_raw(self, sock, x): # type: (socket.socket, int) -> Tuple[bytes, Any, Optional[float]] - """Internal function to receive a Packet""" + """Internal function to receive a Packet. + + :param sock: Socket object from which data are received + :type sock: socket.socket + :param x: Number of bytes to be received + :type x: int + :return: Received bytes, address information and no timestamp + :rtype: Tuple[bytes, Any, Optional[float]] + """ pkt, sa_ll = sock.recvfrom(x) return pkt, sa_ll, None else: @@ -125,6 +140,13 @@ def _recv_raw(self, sock, x): # type: (socket.socket, int) -> Tuple[bytes, Any, Optional[float]] """Internal function to receive a Packet, and process ancillary data. + + :param sock: Socket object from which data are received + :type sock: socket.socket + :param x: Number of bytes to be received + :type x: int + :return: Received bytes, address information and an optional timestamp + :rtype: Tuple[bytes, Any, Optional[float]] """ timestamp = None if not self.auxdata_available: @@ -173,11 +195,26 @@ def _recv_raw(self, sock, x): def recv_raw(self, x=MTU): # type: (int) -> Tuple[Optional[Type[Packet]], Optional[bytes], Optional[float]] # noqa: E501 - """Returns a tuple containing (cls, pkt_data, time)""" + """Returns a tuple containing (cls, pkt_data, time) + + + :param x: Maximum number of bytes to be received, defaults to MTU + :type x: int, optional + :return: A tuple, consisting of a Packet type, the received data, + and a timestamp + :rtype: Tuple[Optional[Type[Packet]], Optional[bytes], Optional[float]] + """ return conf.raw_layer, self.ins.recv(x), None def recv(self, x=MTU, **kwargs): # type: (int, **Any) -> Optional[Packet] + """Receive a Packet according to the `basecls` of this socket + + :param x: Maximum number of bytes to be received, defaults to MTU + :type x: int, optional + :return: The received `Packet` object, or None + :rtype: Optional[Packet] + """ cls, val, ts = self.recv_raw(x) if not val or not cls: return None @@ -201,6 +238,8 @@ def fileno(self): def close(self): # type: () -> None + """Gracefully close this socket + """ if self.closed: return self.closed = True @@ -214,11 +253,15 @@ def close(self): def sr(self, *args, **kargs): # type: (Any, Any) -> Tuple[SndRcvList, PacketList] + """Send and Receive multiple packets + """ from scapy import sendrecv return sendrecv.sndrcv(self, *args, **kargs) def sr1(self, *args, **kargs): # type: (Any, Any) -> Optional[Packet] + """Send one packet and receive one answer + """ from scapy import sendrecv ans = sendrecv.sndrcv(self, *args, **kargs)[0] # type: SndRcvList if len(ans) > 0: