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

Python原始套接字到以太网接口(Windows),python,windows,python-2.7,sockets,dhcp,Python,Windows,Python 2.7,Sockets,Dhcp,我正在尝试创建一个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 addre

我正在尝试创建一个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_数据包无法识别,所以我假设它只适用于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
回溯(最近一次呼叫最后一次):
文件“eth.py”,第27行,在
“你好”)
文件“eth.py”,第19行,在sendeth中
s、 绑定((接口,0))
文件“C:\Python27\lib\socket.py”,第224行,meth格式
返回getattr(self.\u sock,name)(*args)
socket.gaierror:[Errno 11001]getaddrinfo失败

有人知道为什么会发生这种情况吗?

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

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

socket.IPPROTO_RAW
允许您访问3级协议(IP),而以太网位于1级和2级。在第3级,已分析以太网帧,并丢弃其报头。你需要进入第二级,而且
ETH\u P\u ALL
协议似乎是一个很好的起点。我不相信python
socket
模块在那个低级别上实现了它,但是您可以通过
ctypes
模块与WinAPI交互。

文档中的这个示例似乎很有启发性。


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

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


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

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

  • DHCP服务器总是有一些IP地址(以及它可以租用的地址池)
  • 如果客户机需要IP地址和IP地址(DHCP实际上可以做的不仅仅是分配IP地址,现在我们就到此为止),它会发送一个广播DHCPREQUEST,源IP地址为0.0.0.0,目标IP地址为255.255.255.255。服务器也通过UDP广播回答他,但使用他自己的源IP
  • 如果您想创建DHCP的实现,从OSI级别2(以太网)开始只会让您头疼维护级别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端口,需要广播()

    如前所述,
    ETH\u p\u ALL
    由于Win32的限制,未在Windows上实现。 另一种方法称为Winpcap(最近的Npcap),它设置窗口来访问这些低级内容(它添加了一个额外的驱动程序)

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

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

    from scapy.all import *
    IFACES.show() # let’s see what interfaces are available. Windows only
    iface = <<"full iface name">> or <<IFACES.dev_from_index(12)>> or <<IFACES.dev_from_pcapname(r"\\Device_stuff")>>
    socket = conf.L2socket(iface=iface)
    # socket is now an Ethernet socket
    ### RECV
    packet_raw = socket.recv_raw()[0]  # 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
    
    从scapy.all导入*
    IFACES.show()#让我们看看有哪些接口可用。仅限窗口
    iface=或
    socket=conf.L2socket(iface=iface)
    #套接字现在是以太网套接字
    ###记录
    packet_raw=socket.recv_raw()[0]#原始数据
    packet_decoded=socket.recv()#使用库(还包含发送时间等内容)
    ###发送
    socket.send(b“\x00……”)发送原始数据
    socket.send(Ether()/IP(dst=“www.google.com”)/TCP()/Raw(load=b“data”)#使用库
    
    您要为接口传递什么?“eth0”在Windows上不起作用。事实上,根据我对Windows套接字的经验,接口名称通常是不可理解的。甚至还有一个第三方模块来处理它们如果我有多个接口会发生什么?嗯。。。gethostbyname返回一个IP地址。也许可以尝试使用分配给您想要的物理接口的IP地址绑定?当我尝试使用ETH_P__-ALL时,我得到一个错误:AttributeError:“module”对象没有属性“ETH_-P_-ALL”@Sam是的,ETH_-P_-ALL没有在
    套接字中实现。您必须直接使用WinAPI。谢谢。这让我的生活轻松多了。在收到绑定到255.255.255.255的套接字上的消息后,我必须处理该消息并将信息发送回客户端以设置其IP。稍微超出了本线程的范围,您知道描述此交互的位置吗?还是我必须深入研究RFC2131文档?
    
    from scapy.all import *
    IFACES.show() # let’s see what interfaces are available. Windows only
    iface = <<"full iface name">> or <<IFACES.dev_from_index(12)>> or <<IFACES.dev_from_pcapname(r"\\Device_stuff")>>
    socket = conf.L2socket(iface=iface)
    # socket is now an Ethernet socket
    ### RECV
    packet_raw = socket.recv_raw()[0]  # 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