Python Raw Socket to Ethernet Interface (Windows)

16,518

Solution 1

DHCP is a UDP protocol. You shouldn't need a raw socket to implement a DHCP server.

Use an AF_INET/SOCK_DGRAM socket, and bind to address 255.255.255.255 in order to implement your server.

Solution 2

Looks like you don't get access to ethernet with this socket:

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

socket.IPPROTO_RAW gives you access to Level 3 protocol (IP), whereas ethernet is on Level 1 and 2. At level 3 an ethernet frame is already analyzed and its headers discarded. You need to get to Level 2 and ETH_P_ALL protocol seems to be a nice place to start. I don't believe python socket module implements it on that low level, but you can interact with WinAPI via ctypes module.

Solution 3

As said multiple times already, ETH_P_ALL is not implemented on Windows, due to Win32 limitations. The alternative is called Winpcap (more recently Npcap), which sets up Windows to access such low-level things (it adds an extra driver)

What you can do then is to use a Winpcap/Npcap based library such as Scapy, to access Raw low-level sockets. This requires to install Npcap (or Winpcap) on the computer.

Then you can either use the library as-is (it has lots of capabilities of handling packets), or if you want to have access to the raw data

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
Share:
16,518
Sam
Author by

Sam

Updated on July 30, 2022

Comments

  • Sam
    Sam over 1 year

    I'm trying to create a DHCP Server and the first step is for me to send packets through my ethernet port. I'm trying to send packets to my Ethernet interface and having an error popping up.

    The code is below.

    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"))
    

    I was having issues with the way the socket was being created. AF_PACKET is not recognized so I'm assuming that only works for Linux. I commented it out and added a new line below it. I ran it again and I started getting an error shown below.

    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
    

    Does anyone know why this is happening?

  • Sam
    Sam over 7 years
    What would happen if I have multiple interfaces?
  • intrepidhero
    intrepidhero over 7 years
    hmmm... gethostbyname returns an IP address. Maybe try bind with the IP address assigned to the physical interface you want?
  • Sam
    Sam over 7 years
    When I try to use ETH_P_ALL I get an error: AttributeError: 'module' object has no attribute 'ETH_P_ALL'
  • u354356007
    u354356007 over 7 years
    @Sam Yes, ETH_P_ALL isn't implemented in socket. You have to work directly with WinAPI.
  • Sam
    Sam over 7 years
    Thank you. This makes my life a lot easier. After receiving the message on the socket binded to 255.255.255.255 I have to handle the message and send back the information for the client to set it's IP. Slightly out of the scope of this thread, do you know a place that describes this interaction? Or do i have to dive into the RFC2131 documentation?