fail2ban_plugin: jail auto detection improvements
Ilya committed
Mar 26, 2017 at 21:52 UTC
ba298984a7526191f6674c506b3aa2891c05d00e
1 file changed
+42
-45
python.d/fail2ban.chart.py
+42
-45
@@ -11,7 +11,7 @@ import bisect
11
12
priority = 60000
13
retries = 60
14
-REGEX_JAILS = r_compile(r'\[([A-Za-z-_]+)][^\[\]]*?(?<!# )enabled = true')
14
+REGEX_JAILS = r_compile(r'\[([A-Za-z-_]+)][^\[\]]*?(?<!# )enabled = (?:(true|false))')
15
REGEX_DATA = r_compile(r'\[(?P<jail>[a-z]+)\] (?P<ban>[A-Z])[a-z]+ (?P<ipaddr>\d{1,3}(?:\.\d{1,3}){3})')
16
ORDER = ['jails_bans', 'jails_in_jail']
17
@@ -66,19 +66,18 @@ class Service(LogService):
66
if not is_accessible(self.log_path, R_OK):
67
self.error('Cannot access file %s' % self.log_path)
68
return False
69
+
70
+ raw_jails_list = list()
71
jails_list = list()
72
71
- if self.conf_dir:
72
- dir_jails, error = parse_conf_dir(self.conf_dir)
73
- jails_list.extend(dir_jails)
74
- if not dir_jails:
75
- self.error(error)
73
+ for raw_jail in parse_configuration_files(self.conf_path, self.conf_dir, self.error):
74
+ raw_jails_list.extend(raw_jail)
75
77
- if self.conf_path:
78
- path_jails, error = parse_conf_path(self.conf_path)
79
- jails_list.extend(path_jails)
80
- if not path_jails:
81
- self.error(error)
76
+ for jail, status in raw_jails_list:
77
+ if status == 'true' and jail not in jails_list:
78
+ jails_list.append(jail)
79
+ elif status == 'false' and jail in jails_list:
80
+ jails_list.remove(jail)
81
82
# If for some reason parse failed we still can START with default jails_list.
83
self.jails_list = list(set(jails_list) - set(self.exclude)) or ['ssh']
@@ -93,52 +92,50 @@ class Service(LogService):
92
93
def create_dimensions(self):
94
self.definitions = {
96
- 'jails_bans': {'options': [None, 'Jails Ban Statistics', "bans/s", 'bans', 'jail.bans', 'line'],
95
+ 'jails_bans': {'options': [None, 'Jails Ban Statistics', 'bans/s', 'bans', 'jail.bans', 'line'],
96
'lines': []},
97
'jails_in_jail': {'options': [None, 'Banned IPs (since the last restart of netdata)', 'IPs',
99
- 'in jail', 'jail.in_jail', 'line'], 'lines': []},
98
+ 'in jail', 'jail.in_jail', 'line'],
99
+ 'lines': []},
100
}
101
for jail in self.jails_list:
102
self.definitions['jails_bans']['lines'].append([jail, jail, 'incremental'])
103
self.definitions['jails_in_jail']['lines'].append([jail + '_in_jail', jail, 'absolute'])
104
105
+def parse_configuration_files(jails_conf_path, jails_conf_dir, print_error):
106
+ path_conf, path_local, dir_conf, dir_local = list(), list(), list(), list()
107
106
-def parse_conf_dir(conf_dir):
107
- if not isdir(conf_dir):
108
- return list(), '%s is not a directory' % conf_dir
109
-
110
- jail_local = list(filter(lambda local: is_accessible(local, R_OK), glob(conf_dir + '/*.local')))
111
- jail_conf = list(filter(lambda conf: is_accessible(conf, R_OK), glob(conf_dir + '/*.conf')))
112
-
113
- if not (jail_local or jail_conf):
114
- return list(), '%s is empty or not readable' % conf_dir
115
-
116
- # According "man jail.conf" files could be *.local AND *.conf
117
- # *.conf files parsed first. Changes in *.local overrides configuration in *.conf
118
- if jail_conf:
119
- jail_local.extend([conf for conf in jail_conf if conf[:-5] not in [local[:-6] for local in jail_local]])
120
- jails_list = list()
121
- for conf in jail_local:
122
- with open(conf, 'rt') as f:
123
- raw_data = f.read()
124
-
125
- data = ' '.join(raw_data.split())
126
- jails_list.extend(REGEX_JAILS.findall(data))
127
- jails_list = list(set(jails_list))
128
-
129
- return jails_list, 'can\'t locate any jails in %s. Default jail is [\'ssh\']' % conf_dir
108
+ # Parse files in the directory
109
+ if not (isinstance(jails_conf_dir, str) and isdir(jails_conf_dir)):
110
+ print_error('%s is not a directory' % jails_conf_dir)
111
+ else:
112
+ dir_conf = list(filter(lambda conf: is_accessible(conf, R_OK), glob(jails_conf_dir + '/*.conf')))
113
+ dir_local = list(filter(lambda local: is_accessible(local, R_OK), glob(jails_conf_dir + '/*.local')))
114
+ if not (dir_conf or dir_local):
115
+ print_error('%s is empty or not readable' % jails_conf_dir)
116
+ else:
117
+ dir_conf, dir_local = (find_jails_in_files(dir_conf, print_error),
118
+ find_jails_in_files(dir_local, print_error))
119
120
+ # Parse .conf and .local files
121
+ if (isinstance(jails_conf_path, str) and jails_conf_path.endswith(('.local', '.conf'))):
122
+ path_conf, path_local = (find_jails_in_files([jails_conf_path.split('.')[0] + '.conf'], print_error),
123
+ find_jails_in_files([jails_conf_path.split('.')[0] + '.local'], print_error))
124
132
-def parse_conf_path(conf_path):
133
- if not is_accessible(conf_path, R_OK):
134
- return list(), '%s is not readable' % conf_path
125
+ return path_conf, dir_conf, path_local, dir_local
126
136
- with open(conf_path, 'rt') as jails_conf:
137
- raw_data = jails_conf.read()
127
139
- data = raw_data.split()
140
- jails_list = REGEX_JAILS.findall(' '.join(data))
141
- return jails_list, 'can\'t locate any jails in %s. Default jail is [\'ssh\']' % conf_path
128
+def find_jails_in_files(list_of_files, print_error):
129
+ jails_list = list()
130
+ for conf in list_of_files:
131
+ if is_accessible(conf, R_OK):
132
+ with open(conf, 'rt') as f:
133
+ raw_data = f.read()
134
+ data = ' '.join(raw_data.split())
135
+ jails_list.extend(REGEX_JAILS.findall(data))
136
+ else:
137
+ print_error('%s is not readable or not exist' % conf)
138
+ return jails_list
139
140
141
def address_not_in_jail(pool, address, pool_size):