如何从Python中的原始套接字接收数据?

时间:2017-12-01 04:13:53

标签: python sockets networking network-programming raw-sockets

我正在尝试使用套接字库创建一个端口扫描程序(使用SYN数据包)(是的,我知道scapy会使这更容易,但我主要是为了学习练习。)我制作了数据包,成功发送了它,但是我很难接收并解析后续响应。 到目前为止,我已经尝试了s.recv(1024)和4096,以及recvfrom()

s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.sendto(packet, (dstip, 80))
r = s.recv(1024)
print(r)

但是,我在收到响应时遇到问题,我可以看到数据包是通过Wireshark正确发送的,而SYN-ACK是发送到我的机器的,但是我无法正确接收和打印它。有没有更好的方法可以使用s.recv()函数进行此类输入?或者我使用了错误的功能? 任何帮助表示赞赏,我是套接字库的新手。感谢。

2 个答案:

答案 0 :(得分:0)

下面是我在套接字IO的各种来源的帮助下编写的最新模块,从中获取您想要的内容。

import socket
import threading
import time    
import pygogo as gogo    

from icentralsimulator.bridgeio.read_packets import PacketFactory
from icentralsimulator.bridgeio.write_packets import WritePacket
from icentralsimulator.configurations.interfaces import IServerInfoProvider

logger = gogo.Gogo(__name__).logger
send_lock = threading.Lock()


class BridgeConnection:

    def __init__(self, bridge_info_provider: IServerInfoProvider):
        info = bridge_info_provider.get_bridge_server_info()
        self.callback = None
        self.bridge_ip = info.IpAddress
        self.bridge_port = info.Port
        self._connection = None
        self._terminate_wait_for_incoming = False


    @property
    def is_connected(self):
        return self._connection is not None


    def connect(self, callback):
        """
        The purpose of this method is to create (and hold) a connection to the server. At the same time,
        it creates a new thread for the purpose of waiting on incoming packets.
        """
        if self._connection is not None: return
        self._connection = socket.create_connection((self.bridge_ip, self.bridge_port))
        self._connection.settimeout(0.5)

        self.callback = callback

        t = threading.Thread(target=self._wait_for_incoming)
        t.start()
        time.sleep(5)


    def disconnect(self):
        """
        Breaks existing connection to the server if one is currently made and cancels the thread that is waiting
        for incoming packets. If the connection is not currently open, simply returns silently -- thus it is safe
        to call this method repeatedly.
        """
        self._terminate_wait_for_incoming = True
        while self._terminate_wait_for_incoming:
            time.sleep(0.1)
        self._connection.close()
        self._connection = None


    def send_packet(self, packet: WritePacket):
        """
        Sends an arbitrary packet to the server.
        """
        with send_lock:
            logger.debug(f"Sending packet: {packet.payload_plain_text}")
            payload = packet.payload
            self._connection.sendall(payload)


    def _wait_for_incoming(self):

        """
        Continually runs a loop to wait for incoming data on the open socket. If data is received, it is converted
        to a receive packet and forwarded to the consumer as part of a callback.
        """
        self._terminate_wait_for_incoming = False
        buf_len = 4096
        try:
            while not self._terminate_wait_for_incoming:
                data = None
                try:
                    _cnx = self._connection
                    if _cnx is None: break

                    data = _cnx.recv(buf_len)
                    if data is not None and len(data) > 0:

                        while True:
                            new_data = _cnx.recv(buf_len)
                            if new_data is None or len(new_data) == 0:
                                break
                            data = data + new_data

                except socket.timeout:
                    if data is not None and self.callback is not None:
                        packet = PacketFactory.get_packet(data)
                        self.callback(packet)
                        logger.debug(f"Received packet: {data}")
                    time.sleep(0.5)

                except OSError:  # Happens when stopping the application
                    logger.info("Application aborted")
                    return
        finally:
            self._terminate_wait_for_incoming = False

请注意,我不在此处包含IServerInfoProvider或PacketFactory。这些都是我的应用程序的自定义。您需要根据特定用例中的数据包数据来解释数据包。

答案 1 :(得分:0)

Black Hat Python这本书使用套接字库来创建扫描程序,遗憾的是它不是端口扫描程序。他们检查主机是否已启动,并使用原始套接字接收数据。代码可用here

他们在新线程中发送带有一个套接字对象的SYN数据包,并使用另一个套接字对象嗅探回复。

在示例中,他们使用socket.IPPROTO_IPsocket.IPPROTO_ICMP代替socket.IPPROTO_RAW,具体取决于它是否为Windows。

对于嗅探器,他们使用函数setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL , 1)进行嗅探,其中IPPROTO_IP是TCP的虚拟协议,IP_HDRINCL是包含头部的IP数据包,1映射到代码中的ICMP协议。

祝你好运!