~ubuntu-branches/ubuntu/saucy/prewikka/saucy-proposed

« back to all changes in this revision

Viewing changes to sensor.py

  • Committer: Bazaar Package Importer
  • Author(s): Pierre Chifflier
  • Date: 2009-06-14 10:00:20 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20090614100020-479f60e0m8ae7hq0
Tags: 0.9.15-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2004,2005 PreludeIDS Technologies. All Rights Reserved.
 
2
# Author: Nicolas Delon <nicolas.delon@prelude-ids.com>
 
3
#
 
4
# This file is part of the Prewikka program.
 
5
#
 
6
# This program is free software; you can redistribute it and/or modify
 
7
# it under the terms of the GNU General Public License as published by
 
8
# the Free Software Foundation; either version 2, or (at your option)
 
9
# any later version.
 
10
#
 
11
# This program is distributed in the hope that it will be useful,
 
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
# GNU General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU General Public License
 
17
# along with this program; see the file COPYING.  If not, write to
 
18
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 
 
20
 
 
21
import time
 
22
 
 
23
from prewikka import view, User, utils
 
24
 
 
25
 
 
26
class SensorListingParameters(view.Parameters):
 
27
    def register(self):
 
28
        self.optional("filter_path", str)
 
29
        self.optional("filter_value", str)
 
30
 
 
31
 
 
32
 
 
33
class HeartbeatAnalyzeParameters(view.Parameters):
 
34
    def register(self):
 
35
        self.mandatory("analyzerid", long)
 
36
 
 
37
 
 
38
 
 
39
class SensorMessagesDelete(SensorListingParameters):
 
40
    def register(self):
 
41
        SensorListingParameters.register(self)
 
42
        self.optional("analyzerid", list, default=[])
 
43
        self.optional("alerts", str, default=None)
 
44
        self.optional("heartbeats", str, default=None)
 
45
 
 
46
 
 
47
 
 
48
def get_analyzer_status_from_latest_heartbeat(heartbeat_status, heartbeat_time,
 
49
                                              heartbeat_interval, error_margin):
 
50
    if heartbeat_status == "exiting":
 
51
        return "offline", _("Offline")
 
52
 
 
53
    if heartbeat_interval is None:
 
54
        return "unknown", _("Unknown")
 
55
 
 
56
    if time.time() - int(heartbeat_time) > int(heartbeat_interval) + error_margin:
 
57
        return "missing", _("Missing")
 
58
 
 
59
    return "online", _("Online")
 
60
 
 
61
 
 
62
def analyzer_cmp(x, y):
 
63
    xmiss = x["status"] == "missing"
 
64
    ymiss = y["status"] == "missing"
 
65
 
 
66
    if xmiss and ymiss:
 
67
        return cmp(x["name"], y["name"])
 
68
 
 
69
    elif xmiss or ymiss:
 
70
        return ymiss - xmiss
 
71
 
 
72
    else:
 
73
        return cmp(x["name"], y["name"])
 
74
 
 
75
def node_cmp(x, y):
 
76
    xmiss = x["missing"]
 
77
    ymiss = y["missing"]
 
78
 
 
79
    if xmiss or ymiss:
 
80
        return ymiss - xmiss
 
81
    else:
 
82
        return cmp(x["node_name"], y["node_name"])
 
83
 
 
84
 
 
85
def getDominantStatus(d):
 
86
    if d["missing"] > 0 or d["unknown"] > 0:
 
87
        return "missing"
 
88
 
 
89
    return "online"
 
90
 
 
91
 
 
92
class SensorListing(view.View):
 
93
    view_name = "sensor_listing"
 
94
    view_parameters = SensorListingParameters
 
95
    view_permissions = [ User.PERM_IDMEF_VIEW ]
 
96
    view_template = "SensorListing"
 
97
 
 
98
    def init(self, env):
 
99
        self._heartbeat_count = int(env.config.general.getOptionValue("heartbeat_count", 30))
 
100
        self._heartbeat_error_margin = int(env.config.general.getOptionValue("heartbeat_error_margin", 3))
 
101
 
 
102
    def _analyzerPathStr(self, path):
 
103
        s=""
 
104
        for i in path:
 
105
            if len(s) > 0:
 
106
                s += ":"
 
107
 
 
108
            s += str(i)
 
109
 
 
110
        print "PATHSTR=", s
 
111
        return s
 
112
 
 
113
 
 
114
    def render(self):
 
115
        analyzers = { }
 
116
 
 
117
        criteria = None
 
118
        if self.parameters.has_key("filter_path"):
 
119
            criteria = "%s == '%s'" % (self.parameters["filter_path"],
 
120
                                       utils.escape_criteria(self.parameters["filter_value"]))
 
121
 
 
122
        locations = { }
 
123
        nodes = { }
 
124
 
 
125
        for analyzerid in self.env.idmef_db.getAnalyzerids():
 
126
            analyzer = self.env.idmef_db.getAnalyzer(analyzerid)
 
127
 
 
128
            if analyzerid != analyzer["analyzerid"]:
 
129
                print "WARNING!"
 
130
 
 
131
            analyzer["path"] = self._analyzerPathStr(analyzer["path"])
 
132
 
 
133
            parameters = { "analyzerid": analyzer["analyzerid"] }
 
134
            analyzer["alert_listing"] = utils.create_link("sensor_alert_listing", parameters)
 
135
            analyzer["heartbeat_listing"] = utils.create_link("sensor_heartbeat_listing", parameters)
 
136
            analyzer["heartbeat_analyze"] = utils.create_link("heartbeat_analyze", parameters)
 
137
 
 
138
            if analyzer["node_name"]:
 
139
                analyzer["node_name_link"] = utils.create_link(self.view_name,
 
140
                                                               { "filter_path": "heartbeat.analyzer(-1).node.name",
 
141
                                                                 "filter_value": analyzer["node_name"] })
 
142
 
 
143
            if analyzer["node_location"]:
 
144
                analyzer["node_location_link"] = utils.create_link(self.view_name,
 
145
                                                                   { "filter_path": "heartbeat.analyzer(-1).node.location",
 
146
                                                                     "filter_value": analyzer["node_location"] })
 
147
 
 
148
            node_key = ""
 
149
            for i in range(len(analyzer["node_addresses"])):
 
150
                addr = analyzer["node_addresses"][i]
 
151
                node_key += addr
 
152
 
 
153
                analyzer["node_addresses"][i] = {}
 
154
                analyzer["node_addresses"][i]["value"] = addr
 
155
                analyzer["node_addresses"][i]["inline_filter"] = utils.create_link(self.view_name,
 
156
                                                                   { "filter_path": "heartbeat.analyzer(-1).node.address.address",
 
157
                                                                     "filter_value": addr })
 
158
 
 
159
                analyzer["node_addresses"][i]["host_commands"] = []
 
160
                for command in self.env.host_commands.keys():
 
161
                    analyzer["node_addresses"][i]["host_commands"].append((command.capitalize(),
 
162
                                                                           utils.create_link("Command",
 
163
                                                                                             { "origin": self.view_name,
 
164
                                                                                               "command": command, "host": addr })))
 
165
 
 
166
            analyzer["status"], analyzer["status_meaning"] = \
 
167
                                get_analyzer_status_from_latest_heartbeat(analyzer["last_heartbeat_status"],
 
168
                                                                          analyzer["last_heartbeat_time"],
 
169
                                                                          analyzer["last_heartbeat_interval"],
 
170
                                                                          self._heartbeat_error_margin)
 
171
 
 
172
            analyzer["last_heartbeat_time"] = utils.time_to_ymdhms(time.localtime(int(analyzer["last_heartbeat_time"]))) + \
 
173
                                              " %+.2d:%.2d" % utils.get_gmt_offset()
 
174
 
 
175
            node_location = analyzer["node_location"] or _("Node location n/a")
 
176
            node_name = analyzer.get("node_name") or _("Node name n/a")
 
177
            osversion = analyzer["osversion"] or _("OS version n/a")
 
178
            ostype = analyzer["ostype"] or _("OS type n/a")
 
179
            addresses = analyzer["node_addresses"]
 
180
 
 
181
            node_key = node_name + osversion + ostype
 
182
 
 
183
            if not locations.has_key(node_location):
 
184
                locations[node_location] = { "total": 1, "missing": 0, "unknown": 0, "offline": 0, "online": 0, "nodes": { } }
 
185
            else:
 
186
                locations[node_location]["total"] += 1
 
187
 
 
188
            if not locations[node_location]["nodes"].has_key(node_key):
 
189
                locations[node_location]["nodes"][node_key] = { "total": 1, "missing": 0, "unknown": 0, "offline": 0, "online": 0,
 
190
                                                                "analyzers": [ ],
 
191
                                                                "node_name": node_name, "node_location": node_location,
 
192
                                                                "ostype": ostype, "osversion": osversion,
 
193
                                                                "node_addresses": addresses, "node_key": node_key }
 
194
            else:
 
195
                locations[node_location]["nodes"][node_key]["total"] += 1
 
196
 
 
197
            status = analyzer["status"]
 
198
            locations[node_location][status] += 1
 
199
            locations[node_location]["nodes"][node_key][status] += 1
 
200
 
 
201
            if status == "missing" or status == "unknown":
 
202
                locations[node_location]["nodes"][node_key]["analyzers"].insert(0, analyzer)
 
203
            else:
 
204
                locations[node_location]["nodes"][node_key]["analyzers"].append(analyzer)
 
205
 
 
206
        self.dataset["locations"] = locations
 
207
 
 
208
 
 
209
class SensorMessagesDelete(SensorListing):
 
210
    view_name = "sensor_messages_delete"
 
211
    view_parameters = SensorMessagesDelete
 
212
    view_permissions = [ User.PERM_IDMEF_VIEW, User.PERM_IDMEF_ALTER ]
 
213
 
 
214
    def _addToCriteria(self, out, typestr, id, idx):
 
215
        if len(out):
 
216
            out += " && "
 
217
 
 
218
        if id == "None":
 
219
            out += "! %s.analyzer(%d).analyzerid" % (typestr, idx)
 
220
        else:
 
221
            out += "%s.analyzer(%d).analyzerid = '%s'" % (typestr, idx, utils.escape_criteria(id))
 
222
 
 
223
        return out
 
224
 
 
225
    def _genCriteria(self, typestr, analyzerid):
 
226
        idx = 0
 
227
        criteria = ""
 
228
 
 
229
        l = analyzerid.split(":")
 
230
 
 
231
        for id in l[:len(l) -1 ]:
 
232
            criteria = self._addToCriteria(criteria, typestr, id, idx)
 
233
            idx += 1
 
234
 
 
235
        if typestr == "heartbeat":
 
236
            idx = -1
 
237
 
 
238
        return self._addToCriteria(criteria, typestr, l[-1], idx)
 
239
 
 
240
    def render(self):
 
241
        for analyzerid in self.parameters["analyzerid"]:
 
242
            print "STAT ", analyzerid
 
243
 
 
244
            if self.parameters.has_key("alerts"):
 
245
                print self._genCriteria("alert", analyzerid)
 
246
                print "NEWA=", len(self.env.idmef_db.getAlertIdents(self._genCriteria("alert", analyzerid)))
 
247
                print "OLDA=", len(self.env.idmef_db.getAlertIdents("alert.analyzer.analyzerid == '%s'" % utils.escape_criteria(analyzerid.split(":")[-1])))
 
248
 
 
249
            if self.parameters.has_key("heartbeats"):
 
250
                print "--"
 
251
                print "NEWH=", len(self.env.idmef_db.getHeartbeatIdents(self._genCriteria("heartbeat", analyzerid)))
 
252
                print "OLDH=", len(self.env.idmef_db.getHeartbeatIdents("heartbeat.analyzer(-1).analyzerid == '%s'" % utils.escape_criteria(analyzerid.split(":")[-1])))
 
253
 
 
254
#self.env.idmef_db.deleteHeartbeat(self.env.idmef_db.getHeartbeatIdents(criteria))
 
255
 
 
256
        SensorListing.render(self)
 
257
 
 
258
 
 
259
 
 
260
class HeartbeatAnalyze(view.View):
 
261
    view_name = "heartbeat_analyze"
 
262
    view_parameters = HeartbeatAnalyzeParameters
 
263
    view_permissions = [ User.PERM_IDMEF_VIEW ]
 
264
    view_template = "HeartbeatAnalyze"
 
265
 
 
266
    def init(self, env):
 
267
        self._heartbeat_count = int(env.config.general.getOptionValue("heartbeat_count", 30))
 
268
        self._heartbeat_error_margin = int(env.config.general.getOptionValue("heartbeat_error_margin", 3))
 
269
 
 
270
    def render(self):
 
271
        analyzerid = self.parameters["analyzerid"]
 
272
 
 
273
        analyzer = self.env.idmef_db.getAnalyzer(analyzerid)
 
274
        analyzer["last_heartbeat_time"] = str(analyzer["last_heartbeat_time"])
 
275
        analyzer["events"] = [ ]
 
276
        analyzer["status"] = "abnormal_offline"
 
277
        analyzer["status_meaning"] = "abnormal offline"
 
278
 
 
279
        start = time.time()
 
280
        idents = self.env.idmef_db.getHeartbeatIdents(criteria="heartbeat.analyzer(-1).analyzerid == %d" % analyzerid,
 
281
                                                      limit=self._heartbeat_count)
 
282
        newer = None
 
283
        latest = True
 
284
        total_interval = 0
 
285
 
 
286
        for ident in idents:
 
287
            older = self.env.idmef_db.getHeartbeat(ident)
 
288
            older_status = older.getAdditionalData("Analyzer status")
 
289
            older_interval = older["heartbeat.heartbeat_interval"]
 
290
            if not older_status or not older_interval:
 
291
                continue
 
292
            older_time = older["heartbeat.create_time"]
 
293
            total_interval += int(older_interval)
 
294
 
 
295
            if latest:
 
296
                latest = False
 
297
                analyzer["status"], analyzer["status_meaning"] = \
 
298
                                    get_analyzer_status_from_latest_heartbeat(older_status, older_time, older_interval,
 
299
                                                                              self._heartbeat_error_margin)
 
300
                if analyzer["status"] == "abnormal_offline":
 
301
                    analyzer["events"].append({ "value": "sensor is down since %s" % older_time, "type": "down"})
 
302
            if newer:
 
303
                event = None
 
304
 
 
305
                if newer_status == "starting":
 
306
                    if older_status == "exiting":
 
307
                        event = { "value": "normal sensor start at %s" % str(newer_time),
 
308
                                  "type": "start" }
 
309
                    else:
 
310
                        event = { "value": "unexpected sensor restart at %s" % str(newer_time),
 
311
                                  "type": "unexpected_restart" }
 
312
 
 
313
                if newer_status == "running":
 
314
                    if abs(int(newer_time) - int(older_time) - int(older_interval)) > self._heartbeat_error_margin:
 
315
                        event = { "value": "abnormal heartbeat interval between %s and %s" % (str(older_time), str(newer_time)),
 
316
                                  "type": "abnormal_heartbeat_interval" }
 
317
 
 
318
 
 
319
                if newer_status == "exiting":
 
320
                    event = { "value": "normal sensor stop at %s" % str(newer_time),
 
321
                              "type": "normal_stop" }
 
322
 
 
323
                if event:
 
324
                    analyzer["events"].append(event)
 
325
 
 
326
            newer = older
 
327
            newer_status = older_status
 
328
            newer_interval = older_interval
 
329
            newer_time = older_time
 
330
 
 
331
        if not analyzer["events"]:
 
332
            analyzer["events"].append({ "value":
 
333
                                        "No anomaly in the last %d heartbeats (1 heartbeat every %d s average)" %
 
334
                                        (self._heartbeat_count, total_interval / self._heartbeat_count),
 
335
                                        "type": "no_anomaly" })
 
336
 
 
337
        self.dataset["analyzer"] = analyzer