This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Cappie detects new hosts on a network.".
The branch, master has been updated via 39fedabd85a5d9703e7b65204976ee872679ee27 (commit) via d558f1818413756194d4c5abe82b188888a6914e (commit) via e97abe7b434d2d74b683e44d338535c5fc9cca2f (commit) from c39c644181083b102f70f397bb6c6df0aa8f9daa (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit 39fedabd85a5d9703e7b65204976ee872679ee27 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 17 18:09:12 2010 +0200
Add a event that is able to execute shell commands.
commit d558f1818413756194d4c5abe82b188888a6914e Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 17 14:33:31 2010 +0200
Add a global event queue.
This queue is supposed to handle events (that have to be defined later), because we can only handle one event at the same time.
commit e97abe7b434d2d74b683e44d338535c5fc9cca2f Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 17 12:53:15 2010 +0200
Don't check length of arp messages.
It seems as if there are OSes around that send packages with a different length.
-----------------------------------------------------------------------
Summary of changes: cappie.py | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 137 insertions(+), 13 deletions(-)
Difference in files: diff --git a/cappie.py b/cappie.py index 036d70c..5065a9d 100644 --- a/cappie.py +++ b/cappie.py @@ -2,8 +2,10 @@
import logging import logging.handlers +import os import pcapy import struct +import subprocess import sys import time
@@ -49,8 +51,8 @@ def decode_arp_packet(data): 2 : OPERATION_RESPONSE, }
- if not len(data) == 42: - raise DecodeError, "Data has wrong length" + #if not len(data) == 42: + # raise DecodeError, "Data has wrong length: %d" % len(data)
ret = { "type" : TYPE_ARP, @@ -138,13 +140,15 @@ class Database(object): class Interface(Thread): heartbeat = 0.1
- def __init__(self, dev, log, promisc=False, mtu=1500): + def __init__(self, dev, cappie, promisc=False, mtu=1500): Thread.__init__(self)
+ self.cappie = cappie self.dev = dev - self.log = log - self.promisc = promisc + self.log = self.cappie.log self.mtu = mtu + self.promisc = promisc + self.queue = self.cappie.queue
self.db = Database(self)
@@ -202,6 +206,119 @@ class Interface(Thread): return "arp or rarp"
+class QueueFullError(Exception): + pass + + +class Queue(Thread): + heartbeat = 1.0 + maxitems = 100 + + def __init__(self, log): + Thread.__init__(self) + + self.log = log + + self.__running = True + self.__queue = [] + + def __len__(self): + return self.length + + def add(self, event): + if self.length > self.maxitems: + raise QueueFullError, "Cannot queue new event." + + self.__queue.append(event) + + @property + def length(self): + return len(self.__queue) + + def run(self): + self.log.debug("Started event queue") + + while self.__running or self.__queue: + if not self.__queue: + #self.log.debug("Queue sleeping for %s seconds" % self.heartbeat) + time.sleep(self.heartbeat) + continue + + event = self.__queue.pop(0) + self.log.debug("Processing queue event: %s" % event) + try: + event.run() + except EventException, e: + self.log.error("Catched event exception: %s" % e) + + def shutdown(self): + self.__running = False + self.log.debug("Shutting down queue") + self.log.debug("%d events in queue left" % len(self.__queue)) + + # Wait until queue handled all events + self.join() + + +class EventException(Exception): + pass + +class Event(object): + def __init__(self, interface): + self.cappie = interface.cappie + self.interface = interface + self.log = interface.log + + def __str__(self): + return self.__class__.__name__ + + def run(self): + raise NotImplementedError + + +class EventTimeout(EventException): + pass + + +class EventShell(Event): + heartbeat = 0.1 + timeout = 10 + + def __init__(self, interface, script): + Event.__init__(self, interface) + + self.script = script + + def run(self): + args = " ".join([self.script, self.interface.dev]) + + start = time.time() + self.log.debug("Running: %s" % args) + + p = subprocess.Popen(args, + close_fds=True, + shell=True, + stdin=open("/dev/null", "r"), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + while p.poll() is None: + time.sleep(self.heartbeat) + if (time.time() - start) > self.timeout: + try: + os.killpg(p.pid, 9) + except OSError: + pass + raise EventTimeout, "Script took too long to return" + + for line in p.stdout.read().splitlines(): + if not line: continue + self.log.debug(" %s" % line) + + self.cappie.log.debug("Child process returned with exit code: %s" % p.returncode) + return p.returncode + + class Cappie(object): def __init__(self): self.__interfaces = [] @@ -219,10 +336,12 @@ class Cappie(object): handler.setFormatter(logging.Formatter("cappie: %(message)s")) self.log.addHandler(handler)
+ self.queue = Queue(self.log) + self.log.info("Cappie successfully started")
def __del__(self): - self.reset() + self.shutdown() self.log.info("Exiting")
def setDebug(self, debug): @@ -235,18 +354,27 @@ class Cappie(object): if not dev in getAllInterfaces(): raise InterfaceError, "No such interface %s" % dev
- iface = Interface(dev, log=self.log, **kwargs) + kwargs["cappie"] = self + + iface = Interface(dev, **kwargs) self.__interfaces.append(iface)
def run(self): if not self.__interfaces: raise RuntimeError, "No interfaces were configured"
+ # Start queue + self.queue.start() + # Start a thread for each interface for iface in self.__interfaces: iface.start()
while True: + if not self.queue.is_alive(): + self.log.critical("Queue thread died unexpectedly.") + return + for iface in self.__interfaces: if not iface.is_alive(): self.log.critical("Thread died unexpectedly. %s" % iface.dev) @@ -254,8 +382,6 @@ class Cappie(object): time.sleep(60)
def readConfig(self, configfile): - self.reset() - config = ConfigParser() config.read([configfile])
@@ -272,14 +398,12 @@ class Cappie(object): options[option] = value self.addInterface(iface, **options)
- def reset(self): - self.shutdown() - self.__interfaces = [] - def shutdown(self): for iface in self.__interfaces: iface.shutdown()
+ self.queue.shutdown() +
if __name__ == "__main__": from optparse import OptionParser
hooks/post-receive -- Cappie detects new hosts on a network.