Search code examples
pythontcpscapy

Python Scapy L2socket.recv cause infinite PcapTimeoutElapsed exception


I'm using Scapy to send and receive TCP packets. There is a main thread that sends the packets, and another thread that takes care of ACK sending and ACK number update. This is the relevant code from the AckThread class:

    def run(self):
        while not self.event.is_set():
            recv_pkt = None
            received_response=False

            while not received_response:
                try:
                    recv_pkt = self.l2_socket.recv()
                except pcapdnet.PcapTimeoutElapsed:
                    print "except"
                    continue
                if recv_pkt is not None and recv_pkt.haslayer(TCP) and \
                        (recv_pkt.sport == self.tcp_spoofed_conn.tcp_connection.dst_port and
                         recv_pkt.dport == self.tcp_spoofed_conn.tcp_connection.src_port and
                         recv_pkt[IP].src == self.tcp_spoofed_conn.tcp_connection.dst_ip and
                         recv_pkt[IP].dst == self.tcp_spoofed_conn.tcp_connection.src_ip and
                         recv_pkt[Dot1Q].vlan == self.tcp_spoofed_conn.tcp_connection.vlan and
                         recv_pkt[Ether].src == self.tcp_spoofed_conn.tcp_connection.dst_mac and
                         recv_pkt[Ether].dst == self.tcp_spoofed_conn.tcp_connection.src_mac):
                        received_response=True

            if received_response:
                # send ACK to the response

This is how self.L2_socket is defined (I used both L2listen and L2socket and they both didn't work)-

self.l2_socket=conf.L2listen(iface=self.tcp_spoofed_conn.interface)

I use my code to send a TCP packet. There is a response received from the server (I can see it in wireshark), but my code doesn't send ACK to it. Instead, "except" is being printed over and over again, because the code keeps getting the PcapTimeoutElapsed exception, and never reaches the code that send ACK .

Any idea why this is happening and how can I fix it?


Solution

  • I somehow managed to make it work. Few words about this:

    1. I managed to make it work, and the ACK to be sent. Not really sure what was the problem, and maybe it was more than one problem (part of them in the ack sending part).

      This is my working code for reference-

            while not self.event.is_set():
                try:
                    recv_pkt = self.l2_socket.recv()
                except pcapdnet.PcapTimeoutElapsed:
                    print "except"
                    continue
                if recv_pkt is not None and recv_pkt.haslayer(TCP) and \
                        (recv_pkt[TCP].sport == self.tcp_spoofed_conn.tcp_connection.dst_port and
                         recv_pkt[TCP].dport == self.tcp_spoofed_conn.tcp_connection.src_port and
                         recv_pkt[IP].src == self.tcp_spoofed_conn.tcp_connection.dst_ip and
                         recv_pkt[IP].dst == self.tcp_spoofed_conn.tcp_connection.src_ip and
                         recv_pkt[Dot1Q].vlan == self.tcp_spoofed_conn.tcp_connection.vlan and
                         recv_pkt[Ether].src == self.tcp_spoofed_conn.tcp_connection.dst_mac.lower() and
                         recv_pkt[Ether].dst == self.tcp_spoofed_conn.tcp_connection.src_mac.lower()):
    
                    # send ack 
    
    1. Important- the exception is still raised in many of the loop iterations, but the code of the packet receiving is reached in other loop iterations. Meaning- packets are received and being ACKed, and this exception should be ignored
    2. The origin of the exception has something to do with Winpcap used by scapy to read the packets. This is the code of _L2pcapdnetSocket.recv_raw() from scapy\pcapdnet.py
            while pkt is None:
                pkt = self.ins.next()
                if pkt is not None:
                    ts, pkt = pkt
                if pkt is None and scapy.consts.WINDOWS:
                    raise PcapTimeoutElapsed  # To understand this behavior, have a look at L2pcapListenSocket's note  # noqa: E501
    

    and this is the note it references-

                # Note: Timeout with Winpcap/Npcap
                #   The 4th argument of open_pcap corresponds to timeout. In an ideal world, we would  # noqa: E501
                # set it to 0 ==> blocking pcap_next_ex.
                #   However, the way it is handled is very poor, and result in a jerky packet stream.  # noqa: E501
                # To fix this, we set 100 and the implementation under windows is slightly different, as  # noqa: E501
                # everything is always received as non-blocking
                self.ins = open_pcap(iface, MTU, self.promisc, 100, monitor=monitor)  # noqa: E501
    

    So I think there is no real way to avoid this exception, and the only workaround is except it and continue.