@cryptotaxi247 / netdata-1 / commits / ba298984a

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):