]> git.ipfire.org Git - oddments/cappie.git/blob - cappie/__init__.py
Register some handlers to the interface callback function.
[oddments/cappie.git] / cappie / __init__.py
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
22 import logging
23 import logging.handlers
24 import pcapy
25 import time
26
27 from ConfigParser import ConfigParser
28 from threading import Thread
29
30 import protocol
31 import queue
32
33 from errors import *
34 from events import *
35
36 def 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
44 class 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:
96 if not self.queue.isAlive():
97 self.log.critical("Queue thread died unexpectedly.")
98 return
99
100 for iface in self.__interfaces:
101 if not iface.isAlive():
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
129 @property
130 def db(self):
131 return self.queue.db
132
133
134 class 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
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
166 self._handlePacket(p)
167
168 def run(self):
169 self.log.info("Starting interface %s" % self.dev)
170
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:
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
196 def addEvent(self, event):
197 return self.cappie.queue.add(event)
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))