Python 原始套接字到以太网接口 (Windows)

问题描述 投票:0回答:5

我正在尝试创建 DHCP 服务器,第一步是通过以太网端口发送数据包。我正在尝试将数据包发送到我的以太网接口,但弹出错误。

代码如下。

import socket

def sendeth(src, dst, eth_type, payload, interface = "eth0"):
  """Send raw Ethernet packet on interface."""

  assert(len(src) == len(dst) == 6) # 48-bit ethernet addresses
  assert(len(eth_type) == 2) # 16-bit ethernet type

  #s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
  s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)

  # From the docs: "For raw packet
  # sockets the address is a tuple (ifname, proto [,pkttype [,hatype]])"
  s.bind((interface, 0))
  return s.send(src + dst + eth_type + payload)

if __name__ == "__main__":
  print("Sent %d-byte Ethernet packet on eth0" %
    sendeth("\xFE\xED\xFA\xCE\xBE\xEF",
            "\xFE\xED\xFA\xCE\xBE\xEF",
            "\x7A\x05",
            "hello"))

我在创建套接字的方式上遇到了问题。 AF_PACKET 无法识别,所以我假设它仅适用于 Linux。我将其注释掉并在其下面添加了新行。我再次运行它,我开始收到如下所示的错误。

Traceback (most recent call last):
  File "eth.py", line 27, in <module>
    "hello"))
  File "eth.py", line 19, in sendeth
    s.bind((interface, 0))
  File "C:\Python27\lib\socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.gaierror: [Errno 11001] getaddrinfo failed

有谁知道为什么会这样?

python windows python-2.7 sockets dhcp
5个回答
6
投票

正如多次说过的,由于 Win32 的限制,

ETH_P_ALL
未在 Windows 上实现。 另一种方法称为 Winpcap(最近称为 Npcap),它设置 Windows 来访问此类低级事物(它添加了额外的驱动程序)

然后您可以使用基于 Winpcap/Npcap 的 库(例如 Scapy)来访问原始低级套接字。这需要在计算机上安装Npcap(或Winpcap)。

然后您可以按原样使用该库(它具有许多处理数据包的功能),或者如果您想访问原始数据

from scapy.all import *
IFACES.show() # let’s see what interfaces are available. Windows only
iface = <<"full iface name">> or <<conf.ifaces.dev_from_index(12)>> or <<conf.ifaces.dev_from_pcapname(r"\\Device_stuff")>>
socket = conf.L2socket(iface=iface)
# socket is now an Ethernet socket
### RECV
packet_raw = socket.recv_raw()[1]  # Raw data
packet_decoded = socket.recv() # Using the library (also contains things like sent time...)
### SEND
socket.send(b"\x00......"). # send raw data
socket.send(Ether()/IP(dst="www.google.com")/TCP()/Raw(load=b"data")) # use library

幸好这是跨平台的。


4
投票

DHCP 是一种 UDP 协议。您不需要原始套接字来实现 DHCP 服务器。

使用 AF_INET/SOCK_DGRAM 套接字,并绑定到地址 255.255.255.255 以实现您的服务器。


2
投票

看起来您无法使用此套接字访问以太网:

s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)

socket.IPPROTO_RAW
使您可以访问第 3 级协议 (IP),而以太网位于第 1 级和第 2 级。在第 3 级,以太网帧已被分析,其标头已被丢弃。您需要达到第 2 级,而
ETH_P_ALL
协议似乎是一个不错的起点。我不相信 python
socket
模块在那么低的级别上实现它,但您可以通过
ctypes
模块与 WinAPI 交互。


0
投票

文档中的这个示例似乎很有启发性。 https://docs.python.org/2/library/socket.html

import socket

# the public network interface
HOST = socket.gethostbyname(socket.gethostname())

# create a raw socket and bind it to the public interface
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((HOST, 0))

# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

# receive a package
print s.recvfrom(65565)

# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

我认为关键是socket.gethostbyname(socket.gethostname())。 Windows 不支持示例中使用的“eth0”。


0
投票

从另一个方向处理你的问题:为什么你需要使用以太网? DHCP 通常通过 UDP 实现。

  1. DHCP 服务器总是有一些 IP 地址(以及它可以租用的地址池)。
  2. 如果客户端需要 IP(DHCP 实际上可以做的不仅仅是分配 IP,但我们暂时停止此用例),它会发送源 IP 0.0.0.0 和目标 IP 255.255.255.255 的广播 DHCPREQUEST。服务器也通过 UDP 广播回答他,但使用他自己的源 IP。

如果您想创建 DHCP 的实现,从 OSI Level 2(以太网)开始只会让您在维护 Level 3(IP)和 4(UDP)方面感到头疼。我看不出这有什么好处。

如果您想创建一个基于以太网的类似 DHCP 的协议,请准备好解决以下问题:除非要求,否则路由器不会转发广播数据包。例如,对于 Cisco 路由器,它看起来像这样:

router(config)# interface ethernet 0/0
router(config-if)# ip helper-address 10.1.23.5
router(config-if)# end
router#

因此,我们配置路由器,以便它知道有一些有用的连接到 IP 10.1.23.5 的以太网 0/0 端口,需要广播()。

© www.soinside.com 2019 - 2024. All rights reserved.