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 PORT = int(sys.argv) TX_TIME = int(sys.argv) # determine broadcast address bcast_addr = netifaces.ifaddresses(INTERFACE)[netifaces.AF_INET]["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()