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

时间:2016-10-07 19:30:52

标签: 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 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

有谁知道为什么会这样?

5 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

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进行交互。

答案 2 :(得分: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())。 &#34; eth0的&#34;您的示例中使用的内容在Windows上不受支持。

答案 3 :(得分:0)

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

  1. DHCP服务器总是有一些IP地址(以及它可以租用的地址池)。
  2. 如果客户想要和IP(DHCP实际上可以做的不仅仅是分配IP,而是暂时停止使用此用例),它会发送一个广播DHCPREQUEST,其源IP为0.0.0.0,目标IP为255.255.255.255。服务器也通过UDP广播回答他,但使用他自己的源IP。
  3. 如果要创建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#
    

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

答案 4 :(得分:0)

正如多次提到的那样,由于Win32的限制,{strong} ETH_P_ALL在Windows上未实现。 替代方法称为 Winpcap (最近更新为 Npcap ),该方法将Windows设置为访问此类低级内容(它添加了一个额外的驱动程序)

然后,您可以使用基于 Winpcap / Npcap 的库(例如Scapy)来访问Raw低级套接字。这需要在计算机上安装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