【问题标题】:How to receive data from a raw socket in Python?如何从 Python 中的原始套接字接收数据?
【发布时间】:2017-12-01 04:13:52
【问题描述】:

我正在尝试使用套接字库创建一个端口扫描器(使用 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() 函数用于此类输入?还是我使用了错误的功能? 任何帮助表示赞赏,我是套接字库的新手。谢谢。

【问题讨论】:

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


    【解决方案1】:

    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 协议。

    祝你好运!

    【讨论】:

      【解决方案2】:

      以下是我最近在各种套接字 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。这些对我的应用程序来说是非常定制的。您将需要根据特定用例中到达的数据包数据来解释数据包。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-27
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 2022-01-01
      • 1970-01-01
      • 2017-04-09
      相关资源
      最近更新 更多