How Do I Use Raw Socket in Python?

Viewed 112141

I am writing an application to test a network driver for handling corrupted data. And I thought of sending this data using raw socket, so it will not be corrected by the sending machine's TCP-IP stack.

I am writing this application solely on Linux. I have code examples of using raw sockets in system-calls, but I would really like to keep my test as dynamic as possible, and write most if not all of it in Python.

I have googled the web a bit for explanations and examples of the usage of raw sockets in python, but haven't found anything really enlightening. Just a a very old code example that demonstrates the idea, but in no means work.

From what I gathered, Raw Socket usage in Python is nearly identical in semantics to UNIX's raw socket, but without the structs that define the packets structure.

I was wondering if it would even be better not to write the raw socket part of the test in Python, but in C with system-calls, and call it from the main Python code?

8 Answers

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)

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.

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 can use this Python library: rawsocketpy it allows using raw sockets on Layer 2 => No IP/TCP/UDP headers.

#!/usr/bin/env python
from rawsocketpy import RawSocket

sock = RawSocket("wlp2s0", 0xEEFA)
sock.send("some data")
sock.send("personal data", dest="\xAA\xBB\xCC\xDD\xEE\xFF")

or the server form:

#!/usr/bin/env python
from rawsocketpy import RawRequestHandler, RawAsyncServerCallback
import time

def callback(handler, server):
    print("Testing")
    handler.setup()
    handler.handle()
    handler.finish()

class LongTaskTest(RawRequestHandler):
    def handle(self):
        time.sleep(1)
        print(self.packet)

    def finish(self):
        print("End")

    def setup(self):
        print("Begin") 

def main():
    rs = RawAsyncServerCallback("wlp2s0", 0xEEFA, LongTaskTest, callback)
    rs.spin()

if __name__ == '__main__':
    main()

FTR, if you want level 2 access (Ethernet, RadioTap...), that won't be possible natively on Windows (as of today).

If you want to access those with a cross platform method, the go-to choice is libpcap and its Python bindings (as it will use Npcap/WinPcap to work on Windows).

You have a variety of Python bindings available for libpcap, at all sorts of levels (very high or very low).

My advice would be to use the Sockets of scapy (even if you're not using it to dissect), that implement both Native and Libpcap calls, (and let you chose against them with conf.use_pcap = True)

from scapy.all import conf
# conf.use_pcap = True (will be automatic if required)
socket = conf.L2socket(iface="eth0")
# On any platforms, you have `get_if_list()` in `scapy.all` available, to see the ifaces available. You could also ignore it to use the default one
Related