How Do I Use Raw Socket in Python?
Is this the old code you mentioned finding? It looks sensible to me, but I haven't tested it myself (or used raw sockets much). This example from the documentation shows how to use raw sockets to sniff packets, and it looks similar enough.
Sockets system calls (or Winsocks, on Windows), are already wrapped in the standard module socket
: intro, reference.
I've never used raw sockets but it looks like they can be used with this module:
The last example shows how to write a very simple network sniffer with raw sockets on Windows. The example requires administrator privileges to modify the interface:
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)
Eventually the best solution for this case was to write the entire thing in C, because it's not a big application, so it would've incurred greater penalty to write such a small thing in more than 1 language.
After much toying with both the C and python RAW sockets, I eventually preferred the C RAW sockets. RAW sockets require bit-level modifications of less than 8 bit groups for writing the packet headers. Sometimes writing only 4 bits or less. python defines no assistance to this, whereas Linux C has a full API for this.
But I definitely believe that if only this little bit of header initialization was handled conveniently in python, I would've never used C here.
You do it like this:
First you disable your network card's automatic checksumming:
sudo ethtool -K eth1 tx off
And then send your dodgy frame from python 2 (You'll have to convert to Python 3 yourself):
#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
s.bind(("eth1", 0))
# We're putting together an ethernet frame here,
# but you could have anything you want instead
# Have a look at the 'struct' module for more
# flexible packing/unpacking of binary data
# and 'binascii' for 32 bit CRC
src_addr = "\x01\x02\x03\x04\x05\x06"
dst_addr = "\x01\x02\x03\x04\x05\x06"
payload = ("["*30)+"PAYLOAD"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
ethertype = "\x08\x01"
s.send(dst_addr+src_addr+ethertype+payload+checksum)
Done.