Archive

Posts Tagged ‘twisted’

Integrating Twisted with a pcap-based Python packet sniffer

September 8th, 2009

Twisted is an awesome event-driven networking engine. Unfortunately, it does not have good support for interfacing with raw sockets (unlike its support for many network protocols, which is amazing). Anyway, I recently needed to work with raw sockets so I had to find a way to make it work with Twisted. Though Twisted does have a module (twisted.pair) which tries to provide some support for raw sockets, the module is poorly documented and requires a library which is not readily available.

Luckily, I stumbled on a module which works on top of the libpcap packet capture library called pcapy. It is simple to use, and thread-safe — and easy to integrate into a Twisted-based project.

I put together a short sample (see below) which shows how to capture raw packets alongside the main Twisted event loop. It would be trivial to extend this example to also write to a raw socket (using an ordinary Python socket). This example can also be downloaded here.

# This sample shows how to run a libpcap-based packet sniffer concurrently with
# the Twisted framework.  The Twisted component is an "Echo" TCP server
# (listening on port 9999) which prints everything it receives.  When a client
# connects, it starts the pcap thread.  When the pcap thread receives a packet,
# it sends a message to the client telling it the size of the received packet.
# Finally, when the client disconnects the program is terminated.
 
# To try this contrived example out, run this script as root (so that it can use
# pcap) and then connect to the echo server (e.g., telnet localhost 9999).  Note
# that the pcap parameters are hard-coded.  This code uses twisted 8.0.2 and
# pcapy-0.10.4.
 
import os
 
from pcapy import open_live
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
 
# pcap settings
DEV          = 'eth0'  # interface to listen on
MAX_LEN      = 1514    # max size of packet to capture
PROMISCUOUS  = 1       # promiscuous mode?
READ_TIMEOUT = 100     # in milliseconds
PCAP_FILTER  = ''      # empty => get everything (or we could use a BPF filter)
MAX_PKTS     = -1      # number of packets to capture; -1 => no limit
 
def run_pcap(f):
    # the method which will be called when a packet is captured
    def ph(hdr, data):
        print 'pcap heard: when=%s sz=%dB' % (hdr.getts(), len(data))
        # thread safety: call from the main twisted event loop
        reactor.callFromThread(f, len(data))
 
    # start the packet capture
    p = open_live(DEV, MAX_LEN, PROMISCUOUS, READ_TIMEOUT)
    p.setfilter(PCAP_FILTER)
    print "Listening on %s: net=%s, mask=%s" % (DEV, p.getnet(), p.getmask())
    p.loop(MAX_PKTS, ph)
 
# a silly echo server which prints what it receives and sends info about the
# size of each packet captured on DEV
class Echo(Protocol):
    def connectionLost(self, reason):
        os._exit(0) # kill the whole process
 
    def connectionMade(self):
        # run pcap in another thread (it will run forever)
        reactor.callInThread(run_pcap, self.pcapDataReceived)
 
    def dataReceived(self, data):
        print 'echo got: %s' % data
 
    def pcapDataReceived(self, sz):
        self.transport.write('pcap got: %uB\n' % sz)
 
# starts the silly echo server on port 9999
def main():
    factory = Factory()
    factory.protocol = Echo
    reactor.listenTCP(9999, factory)
    reactor.run()
 
if __name__ == "__main__":
    main()

David Underhill Coding, Python , , , , ,

Python + Twisted Length-Type-Based Protocol Client / Server

March 8th, 2009

It seems like I often have a need to work with a simple TCP protocol whose messages have a header which starts with the length of the message and an integer representing the message type (OpenFlow is one of many such protocols). To save myself the trouble of creating and debugging a very similar custom implementation each time I have this need, I decided to package it as a simple Python framework which does this for me. It is based on the event-driven Twised networking engine. Using this simple extension on top of Twisted has a number of benefits:

  1. Automatic handling of the length and type fields when sending and receiving messages.
  2. Automatic unpacking of messages based on type.
  3. Client automatically tries to reconnect if the connection is lost.
  4. Server can handle any number of clients simultaneously.

You can view the official package on the PyPi website here. My local page for the package is here — please view it for an example on how to use this package.

David Underhill Coding, Python, WordPress , , , , ,