1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
# -*- coding: utf-8 -*-
# Description: fail2ban log netdata python.d module
# Author: l2isbad
from base import LogService
from re import compile
try:
from itertools import filterfalse
except ImportError:
from itertools import ifilterfalse as filterfalse
from os import access as is_accessible, R_OK
from os.path import isdir
from glob import glob
priority = 60000
retries = 60
REGEX = compile(r'\[([A-Za-z-_]+)][^\[\]]*?(?<!# )enabled = true')
ORDER = ['jails_group']
class Service(LogService):
def __init__(self, configuration=None, name=None):
LogService.__init__(self, configuration=configuration, name=name)
self.order = ORDER
self.log_path = self.configuration.get('log_path', '/var/log/fail2ban.log')
self.conf_path = self.configuration.get('conf_path', '/etc/fail2ban/jail.local')
self.conf_dir = self.configuration.get('conf_dir', '')
try:
self.exclude = self.configuration['exclude'].split()
except (KeyError, AttributeError):
self.exclude = []
def _get_data(self):
"""
Parse new log lines
:return: dict
"""
try:
raw = self._get_raw_data()
if raw is None:
return None
elif not raw:
return self.data
except (ValueError, AttributeError):
return None
# Fail2ban logs looks like
# 2016-12-25 12:36:04,711 fail2ban.actions[2455]: WARNING [ssh] Ban 178.156.32.231
data = dict(
zip(
self.jails_list,
[len(list(filterfalse(lambda line: (jail + '] Ban') not in line, raw))) for jail in self.jails_list]
))
for jail in data:
self.data[jail] += data[jail]
return self.data
def check(self):
# Check "log_path" is accessible.
# If NOT STOP plugin
if not is_accessible(self.log_path, R_OK):
self.error('Cannot access file %s' % self.log_path)
return False
jails_list = list()
if self.conf_dir:
dir_jails, error = parse_conf_dir(self.conf_dir)
jails_list.extend(dir_jails)
if not dir_jails:
self.error(error)
if self.conf_path:
path_jails, error = parse_conf_path(self.conf_path)
jails_list.extend(path_jails)
if not path_jails:
self.error(error)
# If for some reason parse failed we still can START with default jails_list.
self.jails_list = list(set(jails_list) - set(self.exclude)) or ['ssh']
self.data = dict([(jail, 0) for jail in self.jails_list])
self.create_dimensions()
self.info('Plugin successfully started. Jails: %s' % self.jails_list)
return True
def create_dimensions(self):
self.definitions = {
'jails_group': {'options': [None, "Jails ban statistics", "bans/s", 'jails', 'jail.ban', 'line'],
'lines': []}}
for jail in self.jails_list:
self.definitions['jails_group']['lines'].append([jail, jail, 'incremental'])
def parse_conf_dir(conf_dir):
if not isdir(conf_dir):
return list(), '%s is not a directory' % conf_dir
jail_local = list(filter(lambda local: is_accessible(local, R_OK), glob(conf_dir + '/*.local')))
jail_conf = list(filter(lambda conf: is_accessible(conf, R_OK), glob(conf_dir + '/*.conf')))
if not (jail_local or jail_conf):
return list(), '%s is empty or not readable' % conf_dir
# According "man jail.conf" files could be *.local AND *.conf
# *.conf files parsed first. Changes in *.local overrides configuration in *.conf
if jail_conf:
jail_local.extend([conf for conf in jail_conf if conf[:-5] not in [local[:-6] for local in jail_local]])
jails_list = list()
for conf in jail_local:
with open(conf, 'rt') as f:
raw_data = f.read()
data = ' '.join(raw_data.split())
jails_list.extend(REGEX.findall(data))
jails_list = list(set(jails_list))
return jails_list, 'can\'t locate any jails in %s. Default jail is [\'ssh\']' % conf_dir
def parse_conf_path(conf_path):
if not is_accessible(conf_path, R_OK):
return list(), '%s is not readable' % conf_path
with open(conf_path, 'rt') as jails_conf:
raw_data = jails_conf.read()
data = raw_data.split()
jails_list = REGEX.findall(' '.join(data))
return jails_list, 'can\'t locate any jails in %s. Default jail is [\'ssh\']' % conf_path
|