Jamming WiFi radio channels with Python Twisted

Most of my work aims at reducing interference in WiFi-based multi-hop mesh networks. Since WiFi radios operate in the unlicensed frequency band, external stations and devices might be active there as well, resulting in high interference levels and eventually in a low network performance in terms of throughput. One way to detect such external devices is to measure the channel load (or channel occupany, busy time, ..) based on the carrier sensing statistics of the radio. For testing the efficiency of this method, i implemented a simple traffic generator based on Twisted. The traffic generator’s only function is to create a high load on a given channel by sending out as many frames as possible, thus allowing other network nodes to detect the interferer and the congestion level of the radio channel.

The source code for the traffic generator is attached below. Basically, the traffic generator broadcasts UDP datagrams of 1000 bytes on a specified radio channel as fast as possible. Since the network card needs more time to put the bytes on the air than we can fill its buffer, occasionally socket exceptions are thrown (resource temporarily unavailable). Since we are only interested in creating a high channel load, we simply ignore this and keep on sending messages to the network card.

The efficiency of the jamming script can be tested in a simple experiment. One network node close to the interferer is monitoring the radio channel while the interferer runs the jamming script. Using the functionality of the wireless tools iw, we extract the information about the channel load. The output is as follows

testnode:~$ ./sense wlan1 survey dump
frequency: 5200
noise: 154
channel time: 1968
busy time: 1792
RX time: 1793
TX time: 0

It turns out that the reported channel load is > 90%, showing that the jamming script is quite efficient in creating a high channel load.

!/usr/bin/python
from twisted.internet import reactor, task
from twisted.internet.protocol import DatagramProtocol
from twisted.internet.error import CannotListenError
import socket, netifaces, sys, random

class Jammer(DatagramProtocol):

    def __init__(self, TIME):
        self.TIME = TIME
        self.MESSAGE = ''.join(chr(random.randrange(0, 256)) for i in xrange(1000))

    def startProtocol(self):
        # set broadcast socket option        
        self.transport.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
        reactor.callWhenRunning(self.start_sending)

    def stop_sending(self, t):
        self.transport.stopListening()
        self.stopProtocol()

    def start_sending(self):
        # create task for sending
        t = task.LoopingCall(self.send)
        # set interval to 0 -> send as fast as possible
        t.start(0.0)
        # after self.TIME seconds, stop sending
        reactor.callLater(self.TIME, self.stop_sending, t)

    def stopProtocol(self):
        reactor.callWhenRunning(reactor.stop)

    def send(self):
        try:
            for i in xrange(50):
                self.transport.write(self.MESSAGE, \
                (self.transport.getHost().host, self.transport.getHost().port))
        except:
            # socket throws an exception when the resource is unavailable
            # -> ignore and keep on sending
            pass

if __name__ == "__main__":
    # determine configuration variables
    INTERFACE = sys.argv[1]
    PORT = int(sys.argv[2])
    TX_TIME = int(sys.argv[3])

    # determine broadcast address
    bcast_addr = netifaces.ifaddresses(INTERFACE)[netifaces.AF_INET][0]["broadcast"]

    # create protocol for measurements
    protocol = Jammer(TX_TIME)

    try:
        IListeningPort = reactor.listenUDP(PORT, protocol, bcast_addr)
    except CannotListenError:
        reactor.callWhenRunning(reactor.stop)

    # run event loop
    reactor.run()

Leave a Reply

Your email address will not be published. Required fields are marked *

*