]> git.ipfire.org Git - oddments/cappie.git/blame - cappie/events.py
Merge branch 'master' of ssh://git.ipfire.org/pub/git/oddments/cappie
[oddments/cappie.git] / cappie / events.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 os
23import subprocess
24import time
25
b6f2a21b 26from constants import *
53478050
MT
27from errors import *
28
29class Event(object):
30 def __init__(self, interface):
31 self.cappie = interface.cappie
32 self.interface = interface
33 self.log = interface.log
fe5f16af 34 self.db = self.cappie.db
53478050
MT
35
36 def __str__(self):
37 return self.__class__.__name__
38
be750261
MT
39 def addEvent(self, event):
40 return self.cappie.queue.add(event)
41
53478050
MT
42 def run(self):
43 raise NotImplementedError
44
45
46class EventShell(Event):
47 heartbeat = 0.1
48 timeout = 10
49
50 def __init__(self, interface, script):
51 Event.__init__(self, interface)
52
53 self.script = script
54
55 def run(self):
56 args = " ".join([self.script, self.interface.dev])
57
58 start = time.time()
59 self.log.debug("Running: %s" % args)
60
61 p = subprocess.Popen(args,
62 close_fds=True,
63 shell=True,
64 stdin=open("/dev/null", "r"),
65 stdout=subprocess.PIPE,
66 stderr=subprocess.STDOUT)
67
68 while p.poll() is None:
69 time.sleep(self.heartbeat)
70 if (time.time() - start) > self.timeout:
71 try:
72 os.killpg(p.pid, 9)
73 except OSError:
74 pass
75 raise EventTimeout, "Script took too long to return"
76
77 for line in p.stdout.read().splitlines():
78 if not line: continue
79 self.log.debug(" %s" % line)
80
81 self.cappie.log.debug("Child process returned with exit code: %s" % \
82 p.returncode)
83
84 return p.returncode
b6f2a21b
MT
85
86
87class EventRequestTrigger(Event):
88 def __init__(self, interface, packet):
89 Event.__init__(self, interface)
90
91 self.db = interface.cappie.db
92 self.packet = packet
93
94 def _updateAddress(self, mac, address):
95 where = "WHERE mac = '%s' AND address = '%s'" % (mac, address)
96
97 if self.db.get("SELECT * FROM addresses %s" % where):
98 self.db.execute("UPDATE addresses SET lastseen='%d' %s" % \
99 (time.time(), where))
100 else:
101 self.db.execute("INSERT INTO addresses VALUES('%s', '%s', '%d')" % \
102 (mac, address, time.time()))
103
104 def _updateChanges(self, *args):
105 for arg in args:
106 where = "WHERE address = '%s'" % arg
107 if self.db.get("SELECT * FROM changes %s" % where):
108 self.db.execute("UPDATE changes SET lastchange = '%d' %s" % \
109 (time.time(), where))
110 else:
111 self.db.execute("INSERT INTO changes VALUES('%s', '%d')" % \
112 (arg, time.time()))
113
114 def run(self):
115 mac = self.packet.source_address
116 address = self.packet.source_ip_address
117
118 self._updateAddress(mac, address)
119 self._updateChanges(mac, address)
120
121
122class EventResponseTrigger(EventRequestTrigger):
123 pass
124
125
126class EventGarbageCollector(Event):
127 def __init__(self, db, log):
128 self.db = db
129 self.log = log
130
131 def run(self):
132 # Remove old addresses
133 self.db.execute("DELETE FROM addresses WHERE lastseen >= '%d'" % \
134 (time.time() - DB_LASTSEEN_MAX))
135
136 self.db.commit()
137
138
139class EventCheckDuplicate(Event):
140 def __init__(self, interface, packet):
141 Event.__init__(self, interface)
142 self.packet = packet
143
144 def run(self):
145 entries = self.db.query("SELECT * FROM addresses WHERE address = '%s'" % \
146 self.packet.source_ip_address)
147
148 if not entries:
149 return
150
151 for entry in entries:
152 if self.packet.source_address == entry.mac:
153 entries.remove(entry)
154
155 if len(entries) > 1:
156 self.addEvent(EventHandleDuplicate(self.interface, self.packet))
157
158
159class EventHandleDuplicate(Event):
160 def __init__(self, interface, packet):
161 Event.__init__(self, interface)
162 self.packet = packet
163
164 def run(self):
165 self.log.warning("We probably have a mac spoofing for %s" % \
166 self.packet.source_address)
167
168
169class EventCheckFlipFlop(Event):
170 pass