pcap_twisted.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 
00003 from __future__ import with_statement
00004 
00005 from twisted.internet import reactor
00006 import pcap
00007 import event
00008 import threading
00009 import socket
00010 
00011 class AlreadyClosed(Exception):
00012     pass
00013 
00014 def RawSocket(iface):
00015     # We use this convoluted method so that we can have a filter
00016     # that rejects all packets set.
00017     p = pcap.pcapObject()
00018     p.open_live(iface, 1, 0, 0)
00019     p.setfilter("less 0", 1, 0)
00020     p.setnonblock(True)
00021     import os
00022     #return os.fdopen(p.fileno(),'w',0)
00023     s = socket.fromfd(p.fileno(), socket.PF_PACKET, socket.SOCK_RAW) 
00024     p.open_dead(0, 0)
00025     return s
00026 
00027 class Capture(event.Event):
00028     class _CaptureDescriptor:
00029         def __init__(self, parent, iface = 'any', filter = None, snaplen = 65535, promisc = False, timeout = 10):
00030             self.parent = parent
00031             self.pcap = pcap.pcapObject()
00032             self.pcap.open_live(iface, snaplen, promisc, 0)
00033             if filter is not None:
00034                 self.pcap.setfilter(filter, 1, 0)
00035             self.pcap.setnonblock(True)
00036             reactor.addReader(self)
00037     
00038         def fileno(self):
00039             if self.pcap is None:
00040                 return -1
00041             return self.pcap.fileno()
00042     
00043         def connectionLost(self, reason):
00044             if self.parent:
00045                 self.parent.trigger(None, None, None)
00046     
00047         def logPrefix(self):
00048             return ""
00049 
00050         def _cb(self, *args):
00051             self._got_pkt = True
00052             self.parent.trigger(*args)
00053     
00054         def doRead(self):
00055             print "doRead"
00056             if self.parent:
00057                 self._got_pkt = False
00058                 self.pcap.dispatch(-1, self._cb)
00059                 # If the interface goes down, then the socket will always 
00060                 # be readable, but never contain any data. We catch that
00061                 # case, and assume that it means the socket is closed.
00062                 if not self._got_pkt:
00063                     self.parent.trigger(None, None, None)
00064                     self.close()
00065         
00066         def close(self):
00067             print "Closing descriptor."
00068             reactor.removeReader(self)
00069             self.pcap.open_dead(0, 0)
00070             self.pcap = None
00071             self.parent = None
00072 
00073     def __init__(self, *args, **kwargs):
00074         self._descr = None
00075         self._args = args
00076         self._kwargs = kwargs
00077         self._sub_change_lock = threading.Lock()
00078         event.Event.__init__(self)
00079 
00080     def _subscription_change(self):
00081         with self._sub_change_lock:
00082             has_descr = self._descr is not None
00083             has_subs = len(self._subscribers) != 0
00084             if has_descr and not has_subs:
00085                 print "No more subscribers!"
00086                 self._descr.close()
00087                 self._descr = None
00088             elif not has_descr and has_subs:
00089                 print "Subscribers added!"
00090                 if self._args != None: # We are not closed.
00091                     self._descr = Capture._CaptureDescriptor(self, *self._args, **self._kwargs)
00092                 else:
00093                     # There is a race that lets a subscribe slip through
00094                     # just after close does its unsubscribe_all. This case patches it.
00095                     self.unsubscribe_all(blocking = False)
00096 
00097     def subscribe(self, *args, **kwargs):
00098         if self._args is None:
00099             raise AlreadyClosed("Attempted to subscribe to a closed Capture object.")
00100         return event.Event.subscribe(self, *args, **kwargs)
00101     
00102     def close(self):
00103         with self._sub_change_lock:
00104             self._args = None
00105             self._kwargs = None
00106         self.unsubscribe_all(blocking = False)
00107 
00108     def __enter__(self):
00109         pass
00110 
00111     def __exit__(self, *args):
00112         self.close()
00113 
00114 if __name__ == "__main__":
00115     import scapy.layers.l2
00116     import scapy.layers.inet
00117 
00118     def print_pkt(iface, len, data, time):
00119         print time, iface, len, repr(scapy.layers.l2.Ether(data).payload.payload)
00120 
00121     import gc
00122     def hasPcapObj():
00123         count = 0
00124         for obj in gc.get_objects():
00125             #t = type(obj)
00126             if isinstance(obj, pcap.pcapObject) or \
00127                     isinstance(obj, event.EventCallbackHandle) or \
00128                     isinstance(obj, Capture._CaptureDescriptor) or \
00129                     isinstance(obj, Capture):
00130                 if isinstance(obj, Capture):
00131                     print obj, gc.get_referents(gc.get_referents(obj))
00132                 count += 1
00133         print "objects found:", count
00134    
00135     class DeathReporter:
00136         def __init__(self, name):
00137             self.name = name
00138         
00139         def __del__(self, *args):
00140             print "I'm dead!", self.name
00141 
00142     hasPcapObj()
00143     c1 = Capture('lo', 'icmp')
00144     h = c1.subscribe_repeating(print_pkt, 'lo')
00145     #reactor.callLater(1, hasPcapObj)
00146     #reactor.callLater(2, h.unsubscribe)
00147     #reactor.callLater(3, hasPcapObj)
00148     #reactor.callLater(4, c1.subscribe_repeating, print_pkt, 'lo')
00149     #reactor.callLater(5, hasPcapObj)
00150     #reactor.callLater(6, c1.close)
00151     #reactor.callLater(7, hasPcapObj)
00152     #reactor.callLater(8, c1.subscribe_repeating, print_pkt, 'lo')
00153     #reactor.callLater(9, hasPcapObj)
00154     #print type(h)
00155     #print type(c1)
00156     #print c1.__class__, Capture
00157     #del c1
00158     #del h
00159     reactor.run()
00160     #hasPcapObj()
00161 
00162     


multi_interface_roam
Author(s): Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:15