]> git.ipfire.org Git - oddments/cappie.git/blame - cappie/__init__.py
Register some handlers to the interface callback function.
[oddments/cappie.git] / cappie / __init__.py
CommitLineData
53478050
MT
1#!/usr/bin/python
2###############################################################################
3# #
4# Cappie #
5# Copyright (C) 2010 Michael Tremer #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
22import logging
23import logging.handlers
24import pcapy
25import time
26
27from ConfigParser import ConfigParser
28from threading import Thread
29
30import protocol
31import queue
32
33from errors import *
54e92b60 34from events import *
53478050
MT
35
36def getAllInterfaces():
37 filters = ("lo", "any")
38 ret = []
39 for dev in pcapy.findalldevs():
40 if not dev in filters:
41 ret.append(dev)
42 return ret
43
44class Cappie(object):
45 def __init__(self):
46 self.__interfaces = []
47
48 self.log = logging.getLogger("cappie")
49 self.log.setLevel(logging.INFO)
50
51 # Log to console
52 handler = logging.StreamHandler()
53 handler.setFormatter(logging.Formatter("%(levelname)7s %(message)s"))
54 self.log.addHandler(handler)
55
56 # Setup syslog
57 handler = logging.handlers.SysLogHandler("/dev/log")
58 handler.setFormatter(logging.Formatter("cappie: %(message)s"))
59 self.log.addHandler(handler)
60
61 self.queue = queue.Queue(self.log)
62
63 self.log.info("Cappie successfully started")
64
65 def __del__(self):
66 self.shutdown()
67 self.log.info("Exiting")
68
69 def setDebug(self, debug):
70 if debug:
71 self.log.setLevel(logging.DEBUG)
72 else:
73 self.log.setLevel(logging.INFO)
74
75 def addInterface(self, dev, **kwargs):
76 if not dev in getAllInterfaces():
77 raise InterfaceError, "No such interface %s" % dev
78
79 kwargs["cappie"] = self
80
81 iface = Interface(dev, **kwargs)
82 self.__interfaces.append(iface)
83
84 def run(self):
85 if not self.__interfaces:
86 raise RuntimeError, "No interfaces were configured"
87
88 # Start queue
89 self.queue.start()
90
91 # Start a thread for each interface
92 for iface in self.__interfaces:
93 iface.start()
94
95 while True:
74e192ba 96 if not self.queue.isAlive():
53478050
MT
97 self.log.critical("Queue thread died unexpectedly.")
98 return
99
100 for iface in self.__interfaces:
74e192ba 101 if not iface.isAlive():
53478050
MT
102 self.log.critical("Thread died unexpectedly. %s" % iface.dev)
103 return
104 time.sleep(60)
105
106 def readConfig(self, configfile):
107 config = ConfigParser()
108 config.read([configfile])
109
110 global_opts = {}
111 if config.has_section("global"):
112 for option, value in config.items("global"):
113 global_opts[option] = value
114
115 config.remove_section("global")
116
117 for iface in config.sections():
118 options = {}
119 for option, value in config.items(iface):
120 options[option] = value
121 self.addInterface(iface, **options)
122
123 def shutdown(self):
124 for iface in self.__interfaces:
125 iface.shutdown()
126
127 self.queue.shutdown()
128
497e1b32
MT
129 @property
130 def db(self):
131 return self.queue.db
132
53478050
MT
133
134class Interface(Thread):
135 heartbeat = 0.1
136
137 def __init__(self, dev, cappie, promisc=False, mtu=1500):
138 Thread.__init__(self)
139
140 self.cappie = cappie
141 self.dev = dev
142 self.log = self.cappie.log
143 self.mtu = mtu
144 self.promisc = promisc
145 self.queue = self.cappie.queue
146
53478050
MT
147 self.log.debug("Created new interface %s" % self.dev)
148
149 self.__running = True
150
151 def _callback(self, header, data):
152 self.log.debug("Received packet on %s" % self.dev)
153 try:
154 p = protocol.decode_packet(data)
155 except PacketTypeError, e:
156 self.log.error("Got unknown packet: %s" % e)
157 return
158 except DecodeError, e:
159 self.log.warning("Got decoding error: %s" % e)
160 return
161
162 # Dump packet information
163 for key, val in p.items():
164 self.log.debug(" %s: %s" % (key, val))
165
54e92b60
MT
166 self._handlePacket(p)
167
53478050
MT
168 def run(self):
169 self.log.info("Starting interface %s" % self.dev)
170
53478050
MT
171 p = pcapy.open_live(self.dev, self.mtu, self.promisc, 0)
172 p.setfilter(self.filter)
173 #p.loop(0, self._callback)
174
175 p.setnonblock(1)
176 while True:
177 if not self.__running:
53478050
MT
178 return
179
180 if p.dispatch(1, self._callback):
181 continue
182
183 time.sleep(self.heartbeat)
184
185 def shutdown(self):
186 if not self.__running:
187 return
188
189 self.log.debug("Sending shutdown signal to %s" % self.dev)
190 self.__running = False
191
192 @property
193 def filter(self):
194 return "arp or rarp"
195
ded2591d
MT
196 def addEvent(self, event):
197 return self.cappie.queue.add(event)
54e92b60
MT
198
199 def _handlePacket(self, packet):
200 if packet.operation == OPERATION_RESPONSE:
201 self.addEvent(EventResponseTrigger(self, packet))
202 #self.addEvent(EventCheckDuplicate(self, packet))
203
204 elif packet.operation == OPERATION_REQUEST:
205 self.addEvent(EventRequestTrigger(self, packet))