簡體   English   中英

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

[英]Python Raw Socket to Ethernet Interface (Windows)

我正在嘗試創建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

有誰知道為什么會這樣?

DHCP是UDP協議。 您不應該需要原始套接字來實現DHCP服務器。

使用AF_INET / SOCK_DGRAM套接字,並綁定到地址255.255.255.255以實現您的服務器。

看起來您無法使用此套接字訪問以太網:

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

socket.IPPROTO_RAW使您可以訪問Level 3協議(IP),而ethernet在Level 1和2上。在3級,已經分析了以太網幀並丟棄了其標頭。 你需要達到2級和ETH_P_ALL協議似乎是一個不錯的起點。 我不相信python socket模塊在低級別上實現它,但您可以通過ctypes模塊與WinAPI進行交互。

來自文檔的這個例子似乎很有啟發性。 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”。

從另一個方向接近您的問題:為什么您需要使用以太網? DHCP通常通過UDP實現。

  1. DHCP服務器總是有一些IP地址(以及它可以租用的地址池)。
  2. 如果客戶端需要和IP(DHCP實際上可以做的不僅僅是分配IP,而是暫時停止使用此用例),它會發送一個廣播DHCPREQUEST,其源IP為0.0.0.0,目標IP為255.255.255.255。 服務器也通過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#

因此我們配置路由器,因此它知道有一些有用的東西連接到以太網0/0端口,IP 10.1.23.5需要廣播( )。

如上所述多次,由於Win32限制, 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM